From 05fac53de626be691dfb313e5751eaa849729f29 Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Fri, 30 May 2025 03:07:25 -0700 Subject: [PATCH] Chameleon controller implant (Clothing fast switch) (#33887) * Add the chameleon controller implant * address the issues (Git please dont kill me) * Address the review and fix some merge conflicts! * Cleanup * Add use delay * Silly mistakes * Making a PR at 2 am: Gone wrong * Predict use delay and disable the buttons until you can choose another * First phase custom clothing * Better system, now relays to agent id and mindshield. Chameleon loadouts are a lot better to work with as well * Address the review! No more evil goto * Slams way is better I should have read more closely xD * Some of the jobs * Add to Cargo, CentComm, Service, Passenger, Ninja, Cluwne, Wizard + Minor changes to existing; Add chameleon to bandanas, medals, jugsuits and HUDs * Add everything else * Fix test * Job name * This looks better * Add department organization * Minor cleanup * Added some mindshields * Remove redudent comment and change funcion name to be clearer * Fix cluwne outfit * fix merge conflicts --------- Co-authored-by: SlamBamActionman --- .../Implants/ChameleonControllerSystem.cs | 5 + .../ChameleonControllerBoundUserInterface.cs | 49 ++++++ .../Implants/UI/ChameleonControllerMenu.xaml | 12 ++ .../UI/ChameleonControllerMenu.xaml.cs | 157 ++++++++++++++++++ .../Chameleon/ChameleonJobLoadoutTest.cs | 78 +++++++++ .../Access/Systems/AgentIDCardSystem.cs | 47 ++++++ .../Implants/ChameleonControllerSystem.cs | 151 +++++++++++++++++ Content.Server/PDA/PdaSystem.cs | 10 ++ .../Access/Systems/SharedIdCardSystem.cs | 16 ++ .../ChameleonControllerImplantComponent.cs | 58 +++++++ .../Implants/ChameleonOutfitPrototype.cs | 64 +++++++ .../SharedChameleonControllerSystem.cs | 28 ++++ .../Inventory/InventorySystem.Relay.cs | 2 + .../SharedFakeMindshieldSystem.cs | 55 ++++++ Content.Shared/Roles/Jobs/SharedJobSystem.cs | 39 +++++ .../Station/SharedStationSpawningSystem.cs | 30 ++++ .../chameleon-outfits/chameleon-outfits.ftl | 1 + .../en-US/implant/chameleon-controller.ftl | 1 + Resources/Locale/en-US/job/department.ftl | 2 + Resources/Prototypes/Actions/types.yml | 15 ++ .../Catalog/Fills/Backpacks/duffelbag.yml | 2 +- .../Prototypes/Entities/Clothing/Eyes/hud.yml | 2 + .../Entities/Clothing/Head/bandanas.yml | 1 + .../Entities/Clothing/Neck/medals.yml | 8 + .../Clothing/OuterClothing/hardsuits.yml | 1 + .../Entities/Clothing/OuterClothing/vests.yml | 1 + .../Entities/Objects/Misc/implanters.yml | 8 + .../Objects/Misc/subdermal_implants.yml | 17 ++ .../Loadouts/loadouts_chameleon.yml | 0 Resources/Prototypes/Roles/Antags/ninja.yml | 8 + Resources/Prototypes/Roles/Antags/nukeops.yml | 27 +++ .../Roles/Jobs/Cargo/cargo_technician.yml | 11 ++ .../Roles/Jobs/Cargo/quartermaster.yml | 12 ++ .../Roles/Jobs/Cargo/salvage_specialist.yml | 12 ++ .../Prototypes/Roles/Jobs/CentComm/cburn.yml | 8 + .../Roles/Jobs/CentComm/deathsquad.yml | 8 + .../Jobs/CentComm/emergencyresponseteam.yml | 53 +++++- .../Roles/Jobs/CentComm/official.yml | 9 + .../Roles/Jobs/Civilian/assistant.yml | 11 ++ .../Roles/Jobs/Civilian/bartender.yml | 12 ++ .../Roles/Jobs/Civilian/botanist.yml | 11 ++ .../Roles/Jobs/Civilian/chaplain.yml | 12 ++ .../Prototypes/Roles/Jobs/Civilian/chef.yml | 12 ++ .../Prototypes/Roles/Jobs/Civilian/clown.yml | 10 ++ .../Roles/Jobs/Civilian/janitor.yml | 11 ++ .../Prototypes/Roles/Jobs/Civilian/lawyer.yml | 11 ++ .../Roles/Jobs/Civilian/librarian.yml | 11 ++ .../Prototypes/Roles/Jobs/Civilian/mime.yml | 9 + .../Roles/Jobs/Civilian/musician.yml | 10 ++ .../Roles/Jobs/Civilian/service_worker.yml | 11 ++ .../Prototypes/Roles/Jobs/Command/captain.yml | 10 ++ .../Roles/Jobs/Command/head_of_personnel.yml | 12 ++ .../Engineering/atmospheric_technician.yml | 10 ++ .../Roles/Jobs/Engineering/chief_engineer.yml | 12 ++ .../Jobs/Engineering/station_engineer.yml | 11 ++ .../Jobs/Engineering/technical_assistant.yml | 11 ++ .../Prototypes/Roles/Jobs/Fun/cluwne.yml | 11 ++ Resources/Prototypes/Roles/Jobs/Fun/sus.yml | 17 ++ .../Roles/Jobs/Fun/wizard_startinggear.yml | 10 ++ .../Prototypes/Roles/Jobs/Medical/chemist.yml | 10 ++ .../Jobs/Medical/chief_medical_officer.yml | 12 ++ .../Roles/Jobs/Medical/medical_doctor.yml | 11 ++ .../Roles/Jobs/Medical/medical_intern.yml | 11 ++ .../Roles/Jobs/Medical/paramedic.yml | 11 ++ .../Roles/Jobs/Science/research_assistant.yml | 11 ++ .../Roles/Jobs/Science/research_director.yml | 12 ++ .../Roles/Jobs/Science/scientist.yml | 11 ++ .../Roles/Jobs/Security/detective.yml | 10 ++ .../Roles/Jobs/Security/head_of_security.yml | 8 + .../Roles/Jobs/Security/security_cadet.yml | 12 ++ .../Roles/Jobs/Security/security_officer.yml | 10 ++ .../Prototypes/Roles/Jobs/Security/warden.yml | 14 ++ .../Prototypes/Roles/Jobs/Wildcards/boxer.yml | 11 ++ .../Roles/Jobs/Wildcards/psychologist.yml | 12 ++ .../Roles/Jobs/Wildcards/reporter.yml | 11 ++ .../Roles/Jobs/Wildcards/zookeeper.yml | 12 ++ Resources/Prototypes/tags.yml | 3 + .../Implants/implants.rsi/chameleon.png | Bin 0 -> 871 bytes .../Actions/Implants/implants.rsi/meta.json | 5 +- 79 files changed, 1437 insertions(+), 3 deletions(-) create mode 100644 Content.Client/Implants/ChameleonControllerSystem.cs create mode 100644 Content.Client/Implants/UI/ChameleonControllerBoundUserInterface.cs create mode 100644 Content.Client/Implants/UI/ChameleonControllerMenu.xaml create mode 100644 Content.Client/Implants/UI/ChameleonControllerMenu.xaml.cs create mode 100644 Content.IntegrationTests/Tests/Chameleon/ChameleonJobLoadoutTest.cs create mode 100644 Content.Server/Implants/ChameleonControllerSystem.cs create mode 100644 Content.Shared/Implants/ChameleonControllerImplantComponent.cs create mode 100644 Content.Shared/Implants/ChameleonOutfitPrototype.cs create mode 100644 Content.Shared/Implants/SharedChameleonControllerSystem.cs create mode 100644 Resources/Locale/en-US/chameleon-outfits/chameleon-outfits.ftl create mode 100644 Resources/Locale/en-US/implant/chameleon-controller.ftl create mode 100644 Resources/Prototypes/Loadouts/loadouts_chameleon.yml create mode 100644 Resources/Prototypes/Roles/Jobs/Fun/sus.yml create mode 100644 Resources/Textures/Actions/Implants/implants.rsi/chameleon.png diff --git a/Content.Client/Implants/ChameleonControllerSystem.cs b/Content.Client/Implants/ChameleonControllerSystem.cs new file mode 100644 index 0000000000..7db4b37ef2 --- /dev/null +++ b/Content.Client/Implants/ChameleonControllerSystem.cs @@ -0,0 +1,5 @@ +using Content.Shared.Implants; + +namespace Content.Client.Implants; + +public sealed partial class ChameleonControllerSystem : SharedChameleonControllerSystem; diff --git a/Content.Client/Implants/UI/ChameleonControllerBoundUserInterface.cs b/Content.Client/Implants/UI/ChameleonControllerBoundUserInterface.cs new file mode 100644 index 0000000000..42b891ff50 --- /dev/null +++ b/Content.Client/Implants/UI/ChameleonControllerBoundUserInterface.cs @@ -0,0 +1,49 @@ +using Content.Shared.Clothing; +using Content.Shared.Implants; +using Content.Shared.Preferences.Loadouts; +using Content.Shared.Roles; +using Content.Shared.Timing; +using JetBrains.Annotations; +using Robust.Client.UserInterface; +using Robust.Shared.Prototypes; + +namespace Content.Client.Implants.UI; + +[UsedImplicitly] +public sealed class ChameleonControllerBoundUserInterface : BoundUserInterface +{ + private readonly UseDelaySystem _delay; + + [ViewVariables] + private ChameleonControllerMenu? _menu; + + public ChameleonControllerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + _delay = EntMan.System(); + } + + protected override void Open() + { + base.Open(); + + _menu = this.CreateWindow(); + _menu.OnJobSelected += OnJobSelected; + } + + private void OnJobSelected(ProtoId outfit) + { + if (!EntMan.TryGetComponent(Owner, out var useDelayComp)) + return; + + if (!_delay.TryResetDelay((Owner, useDelayComp), true)) + return; + + SendMessage(new ChameleonControllerSelectedOutfitMessage(outfit)); + + if (!_delay.TryGetDelayInfo((Owner, useDelayComp), out var delay) || _menu == null) + return; + + _menu._lockedUntil = DateTime.Now.Add(delay.Length); + _menu.UpdateGrid(true); + } +} diff --git a/Content.Client/Implants/UI/ChameleonControllerMenu.xaml b/Content.Client/Implants/UI/ChameleonControllerMenu.xaml new file mode 100644 index 0000000000..39322a2991 --- /dev/null +++ b/Content.Client/Implants/UI/ChameleonControllerMenu.xaml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/Content.Client/Implants/UI/ChameleonControllerMenu.xaml.cs b/Content.Client/Implants/UI/ChameleonControllerMenu.xaml.cs new file mode 100644 index 0000000000..a41e2e9293 --- /dev/null +++ b/Content.Client/Implants/UI/ChameleonControllerMenu.xaml.cs @@ -0,0 +1,157 @@ +using System.Linq; +using System.Numerics; +using Content.Client.Roles; +using Content.Client.Stylesheets; +using Content.Client.UserInterface.Controls; +using Content.Shared.Implants; +using Content.Shared.StatusIcon; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Client.Implants.UI; + +[GenerateTypedNameReferences] +public sealed partial class ChameleonControllerMenu : FancyWindow +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + private readonly SpriteSystem _sprite; + private readonly JobSystem _job; + + // List of all the job protos that you can select! + private IEnumerable _outfits; + + // Lock the UI until this time + public DateTime? _lockedUntil; + + private static readonly ProtoId UnknownIcon = "JobIconUnknown"; + private static readonly LocId UnknownDepartment = "department-Unknown"; + + public event Action>? OnJobSelected; + + public ChameleonControllerMenu() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + _sprite = _entityManager.System(); + _job = _entityManager.System(); + + _outfits = _prototypeManager.EnumeratePrototypes(); + + UpdateGrid(); + } + + /// + /// Fill the grid with the correct job icons and buttons. + /// + /// Set to true to disable all the buttons. + public void UpdateGrid(bool disabled = false) + { + Grid.RemoveAllChildren(); + + // Dictionary to easily put outfits in departments. + // Department name -> UI element holding that department. + var departments = new Dictionary(); + + departments.Add(UnknownDepartment, CreateDepartment(UnknownDepartment)); + + // Go through every outfit and add them to the correct department. + foreach (var outfit in _outfits) + { + _prototypeManager.TryIndex(outfit.Job, out var jobProto); + + var name = outfit.LoadoutName ?? outfit.Name ?? jobProto?.Name ?? "Prototype has no name or job."; + + var jobIconId = outfit.Icon ?? jobProto?.Icon ?? UnknownIcon; + var jobIconProto = _prototypeManager.Index(jobIconId); + + var outfitButton = CreateOutfitButton(disabled, name, jobIconProto, outfit.ID); + + if (outfit.Job != null && _job.TryGetLowestWeightDepartment(outfit.Job, out var departmentPrototype)) + { + if (!departments.ContainsKey(departmentPrototype.Name)) + departments.Add(departmentPrototype.Name, CreateDepartment(departmentPrototype.Name)); + + departments[departmentPrototype.Name].AddChild(outfitButton); + } + else + { + departments[UnknownDepartment].AddChild(outfitButton); + } + } + + // Sort the departments by their weight. + var departmentList = departments.ToList(); + departmentList.Sort((a, b) => a.Value.ChildCount.CompareTo(b.Value.ChildCount)); + + // Actually add the departments to the window. + foreach (var department in departmentList) + { + Grid.AddChild(department.Value); + } + } + + private BoxContainer CreateDepartment(string name) + { + var departmentContainer = new BoxContainer + { + Orientation = BoxContainer.LayoutOrientation.Vertical, + }; + departmentContainer.AddChild(new Label + { + Text = Loc.GetString(name), + }); + + return departmentContainer; + } + + private BoxContainer CreateOutfitButton(bool disabled, string name, JobIconPrototype jobIconProto, ProtoId outfitProto) + { + var outfitButton = new BoxContainer(); + + var button = new Button + { + HorizontalExpand = true, + StyleClasses = {StyleBase.ButtonSquare}, + ToolTip = Loc.GetString(name), + Text = Loc.GetString(name), + Margin = new Thickness(0, 0, 15, 0), + Disabled = disabled, + }; + + var jobIconTexture = new TextureRect + { + Texture = _sprite.Frame0(jobIconProto.Icon), + TextureScale = new Vector2(2.5f, 2.5f), + Stretch = TextureRect.StretchMode.KeepCentered, + Margin = new Thickness(0, 0, 5, 0), + }; + + outfitButton.AddChild(jobIconTexture); + outfitButton.AddChild(button); + + button.OnPressed += _ => JobButtonPressed(outfitProto); + + return outfitButton; + } + + private void JobButtonPressed(ProtoId outfit) + { + OnJobSelected?.Invoke(outfit); + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + if (_lockedUntil == null || DateTime.Now < _lockedUntil) + return; + + _lockedUntil = null; + UpdateGrid(); + } +} diff --git a/Content.IntegrationTests/Tests/Chameleon/ChameleonJobLoadoutTest.cs b/Content.IntegrationTests/Tests/Chameleon/ChameleonJobLoadoutTest.cs new file mode 100644 index 0000000000..da061f052a --- /dev/null +++ b/Content.IntegrationTests/Tests/Chameleon/ChameleonJobLoadoutTest.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Text; +using Content.Client.Implants; +using Content.IntegrationTests.Tests.Interaction; +using Content.Shared.Clothing; +using Content.Shared.Implants; +using Content.Shared.Preferences.Loadouts; +using Content.Shared.Roles; +using Robust.Shared.Prototypes; + +namespace Content.IntegrationTests.Tests.Chameleon; + +/// +/// Ensures all round "round start jobs" have an associated chameleon loadout. +/// +public sealed class ChameleonJobLoadoutTest : InteractionTest +{ + private readonly List> JobBlacklist = + [ + + ]; + + [Test] + public async Task CheckAllJobs() + { + var alljobs = ProtoMan.EnumeratePrototypes(); + + // Job -> number of references + Dictionary, int> validJobs = new(); + + // Only add stuff that actually has clothing! We don't want stuff like AI or borgs. + foreach (var job in alljobs) + { + if (!IsProbablyRoundStartJob(job) || JobBlacklist.Contains(job.ID)) + continue; + + validJobs.Add(job.ID, 0); + } + + var chameleons = ProtoMan.EnumeratePrototypes(); + + foreach (var chameleon in chameleons) + { + if (chameleon.Job == null || !validJobs.ContainsKey(chameleon.Job.Value)) + continue; + + validJobs[chameleon.Job.Value] += 1; + } + + var errorMessage = new StringBuilder(); + errorMessage.AppendLine("The following job(s) have no chameleon prototype(s):"); + var invalid = false; + + // All round start jobs have a chameleon loadout + foreach (var job in validJobs) + { + if (job.Value != 0) + continue; + + errorMessage.AppendLine(job.Key + " has no chameleonOutfit prototype."); + invalid = true; + } + + if (!invalid) + return; + + Assert.Fail(errorMessage.ToString()); + } + + /// + /// Best guess at what a "round start" job is. + /// + private bool IsProbablyRoundStartJob(JobPrototype job) + { + return job.StartingGear != null && ProtoMan.HasIndex(LoadoutSystem.GetJobPrototype(job.ID)); + } + +} diff --git a/Content.Server/Access/Systems/AgentIDCardSystem.cs b/Content.Server/Access/Systems/AgentIDCardSystem.cs index 9ede128a5a..6385274336 100644 --- a/Content.Server/Access/Systems/AgentIDCardSystem.cs +++ b/Content.Server/Access/Systems/AgentIDCardSystem.cs @@ -9,6 +9,11 @@ using Robust.Server.GameObjects; using Robust.Shared.Prototypes; using Content.Shared.Roles; using System.Diagnostics.CodeAnalysis; +using Content.Server.Clothing.Systems; +using Content.Server.Implants; +using Content.Shared.Implants; +using Content.Shared.Inventory; +using Content.Shared.PDA; namespace Content.Server.Access.Systems { @@ -18,6 +23,8 @@ namespace Content.Server.Access.Systems [Dependency] private readonly IdCardSystem _cardSystem = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly ChameleonClothingSystem _chameleon = default!; + [Dependency] private readonly ChameleonControllerSystem _chamController = default!; public override void Initialize() { @@ -28,6 +35,46 @@ namespace Content.Server.Access.Systems SubscribeLocalEvent(OnNameChanged); SubscribeLocalEvent(OnJobChanged); SubscribeLocalEvent(OnJobIconChanged); + SubscribeLocalEvent>(OnChameleonControllerOutfitChangedItem); + } + + private void OnChameleonControllerOutfitChangedItem(Entity ent, ref InventoryRelayedEvent args) + { + if (!TryComp(ent, out var idCardComp)) + return; + + _prototypeManager.TryIndex(args.Args.ChameleonOutfit.Job, out var jobProto); + + var jobIcon = args.Args.ChameleonOutfit.Icon ?? jobProto?.Icon; + var jobName = args.Args.ChameleonOutfit.Name ?? jobProto?.Name ?? ""; + + if (jobIcon != null) + _cardSystem.TryChangeJobIcon(ent, _prototypeManager.Index(jobIcon.Value), idCardComp); + + if (jobName != "") + _cardSystem.TryChangeJobTitle(ent, Loc.GetString(jobName), idCardComp); + + // If you have forced departments use those over the jobs actual departments. + if (args.Args.ChameleonOutfit?.Departments?.Count > 0) + _cardSystem.TryChangeJobDepartment(ent, args.Args.ChameleonOutfit.Departments, idCardComp); + else if (jobProto != null) + _cardSystem.TryChangeJobDepartment(ent, jobProto, idCardComp); + + // Ensure that you chameleon IDs in PDAs correctly. Yes this is sus... + + // There is one weird interaction: If the job / icon don't match the PDAs job the chameleon will be updated + // to the PDAs IDs sprite but the icon and job title will not match. There isn't a way to get around this + // really as there is no tie between job -> pda or pda -> job. + + var idSlotGear = _chamController.GetGearForSlot(args, "id"); + if (idSlotGear == null) + return; + + var proto = _prototypeManager.Index(idSlotGear); + if (!proto.TryGetComponent(out var comp, EntityManager.ComponentFactory)) + return; + + _chameleon.SetSelectedPrototype(ent, comp.IdCard); } private void OnAfterInteract(EntityUid uid, AgentIDCardComponent component, AfterInteractEvent args) diff --git a/Content.Server/Implants/ChameleonControllerSystem.cs b/Content.Server/Implants/ChameleonControllerSystem.cs new file mode 100644 index 0000000000..9e876f9399 --- /dev/null +++ b/Content.Server/Implants/ChameleonControllerSystem.cs @@ -0,0 +1,151 @@ +using Content.Server.Clothing.Systems; +using Content.Server.Preferences.Managers; +using Content.Shared.Clothing; +using Content.Shared.Clothing.Components; +using Content.Shared.Implants; +using Content.Shared.Implants.Components; +using Content.Shared.Interaction; +using Content.Shared.Inventory; +using Content.Shared.Preferences; +using Content.Shared.Preferences.Loadouts; +using Content.Shared.Roles; +using Content.Shared.Station; +using Content.Shared.Timing; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; + +namespace Content.Server.Implants; + +public sealed class ChameleonControllerSystem : SharedChameleonControllerSystem +{ + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly SharedStationSpawningSystem _stationSpawningSystem = default!; + [Dependency] private readonly ChameleonClothingSystem _chameleonClothingSystem = default!; + [Dependency] private readonly IServerPreferencesManager _preferences = default!; + [Dependency] private readonly UseDelaySystem _delay = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnSelected); + + SubscribeLocalEvent>(ChameleonControllerOutfitItemSelected); + } + + private void OnSelected(Entity ent, ref ChameleonControllerSelectedOutfitMessage args) + { + if (!_delay.TryResetDelay(ent.Owner, true) || ent.Comp.ImplantedEntity == null || !HasComp(ent)) + return; + + ChangeChameleonClothingToOutfit(ent.Comp.ImplantedEntity.Value, args.SelectedChameleonOutfit); + } + + /// + /// Switches all the chameleon clothing that the implant user is wearing to look like the selected job. + /// + private void ChangeChameleonClothingToOutfit(EntityUid user, ProtoId outfit) + { + var outfitPrototype = _proto.Index(outfit); + + _proto.TryIndex(outfitPrototype.Job, out var jobPrototype); + _proto.TryIndex(outfitPrototype.StartingGear, out var startingGearPrototype); + + GetJobEquipmentInformation(jobPrototype, user, out var customRoleLoadout, out var defaultRoleLoadout, out var jobStartingGearPrototype); + + var ev = new ChameleonControllerOutfitSelectedEvent( + outfitPrototype, + customRoleLoadout, + defaultRoleLoadout, + jobStartingGearPrototype, + startingGearPrototype + ); + + RaiseLocalEvent(user, ref ev); + } + + // This gets as much information from the job as it can. + // E.g. the players profile, the default equipment for that job etc... + private void GetJobEquipmentInformation( + JobPrototype? jobPrototype, + EntityUid? user, + out RoleLoadout? customRoleLoadout, + out RoleLoadout? defaultRoleLoadout, + out StartingGearPrototype? jobStartingGearPrototype) + { + customRoleLoadout = null; + defaultRoleLoadout = null; + jobStartingGearPrototype = null; + + if (jobPrototype == null) + return; + + _proto.TryIndex(jobPrototype.StartingGear, out jobStartingGearPrototype); + + if (!TryComp(user, out var actorComponent)) + return; + + var userId = actorComponent.PlayerSession.UserId; + var prefs = _preferences.GetPreferences(userId); + + if (prefs.SelectedCharacter is not HumanoidCharacterProfile profile) + return; + + var jobProtoId = LoadoutSystem.GetJobPrototype(jobPrototype.ID); + + profile.Loadouts.TryGetValue(jobProtoId, out customRoleLoadout); + + if (!_proto.HasIndex(jobProtoId)) + return; + + defaultRoleLoadout = new RoleLoadout(jobProtoId); + defaultRoleLoadout.SetDefault(profile, null, _proto); // only sets the default if the player has no loadout + } + + private void ChameleonControllerOutfitItemSelected(Entity ent, ref InventoryRelayedEvent args) + { + if (!_inventory.TryGetContainingSlot(ent.Owner, out var slot)) + return; + + _chameleonClothingSystem.SetSelectedPrototype(ent, GetGearForSlot(args, slot.Name), component: ent.Comp); + } + + public string? GetGearForSlot(InventoryRelayedEvent ev, string slotName) + { + return GetGearForSlot(ev.Args.ChameleonOutfit, ev.Args.CustomRoleLoadout, ev.Args.DefaultRoleLoadout, ev.Args.JobStartingGearPrototype, ev.Args.StartingGearPrototype, slotName); + } + + /// + /// Get the gear for the given slot. The priority is: + ///
1.) Custom loadout from the player for the slot. + ///
2.) Chameleon outfit slot equipment. + ///
3.) Chameleon outfit starting gear equipment. + ///
4.) Default job equipment. + ///
5.) Staring equipment for that job. + ///
+ /// The entity (as a protoid) if there is gear for that slot, null if there isn't. + public string? GetGearForSlot(ChameleonOutfitPrototype? chameleonOutfitPrototype, RoleLoadout? customRoleLoadout, RoleLoadout? defaultRoleLoadout, StartingGearPrototype? jobStartingGearPrototype, StartingGearPrototype? startingGearPrototype, string slotName) + { + var customLoadoutGear = _stationSpawningSystem.GetGearForSlot(customRoleLoadout, slotName); + if (customLoadoutGear != null) + return customLoadoutGear; + + if (chameleonOutfitPrototype != null && chameleonOutfitPrototype.Equipment.TryGetValue(slotName, out var forSlot)) + return forSlot; + + var startingGear = startingGearPrototype != null ? ((IEquipmentLoadout)startingGearPrototype).GetGear(slotName) : ""; + if (startingGear != "") + return startingGear; + + var defaultLoadoutGear = _stationSpawningSystem.GetGearForSlot(defaultRoleLoadout, slotName); + if (defaultLoadoutGear != null) + return defaultLoadoutGear; + + var jobStartingGear = jobStartingGearPrototype != null ? ((IEquipmentLoadout)jobStartingGearPrototype).GetGear(slotName) : ""; + if (jobStartingGear != "") + return jobStartingGear; + + return null; + } +} diff --git a/Content.Server/PDA/PdaSystem.cs b/Content.Server/PDA/PdaSystem.cs index bfa8e1825d..282290e469 100644 --- a/Content.Server/PDA/PdaSystem.cs +++ b/Content.Server/PDA/PdaSystem.cs @@ -11,6 +11,8 @@ using Content.Shared.Access.Components; using Content.Shared.CartridgeLoader; using Content.Shared.Chat; using Content.Shared.DeviceNetwork.Components; +using Content.Shared.Implants; +using Content.Shared.Inventory; using Content.Shared.Light; using Content.Shared.Light.EntitySystems; using Content.Shared.PDA; @@ -56,6 +58,14 @@ namespace Content.Server.PDA SubscribeLocalEvent(OnStationRenamed); SubscribeLocalEvent(OnEntityRenamed, after: new[] { typeof(IdCardSystem) }); SubscribeLocalEvent(OnAlertLevelChanged); + SubscribeLocalEvent>(ChameleonControllerOutfitItemSelected); + } + + private void ChameleonControllerOutfitItemSelected(Entity ent, ref InventoryRelayedEvent args) + { + // Relay it to your ID so it can update as well. + if (ent.Comp.ContainedId != null) + RaiseLocalEvent(ent.Comp.ContainedId.Value, args); } private void OnEntityRenamed(ref EntityRenamedEvent ev) diff --git a/Content.Shared/Access/Systems/SharedIdCardSystem.cs b/Content.Shared/Access/Systems/SharedIdCardSystem.cs index a2f59a5a34..dd603cbb02 100644 --- a/Content.Shared/Access/Systems/SharedIdCardSystem.cs +++ b/Content.Shared/Access/Systems/SharedIdCardSystem.cs @@ -204,6 +204,22 @@ public abstract class SharedIdCardSystem : EntitySystem return true; } + public bool TryChangeJobDepartment(EntityUid uid, List> departments, IdCardComponent? id = null) + { + if (!Resolve(uid, ref id)) + return false; + + id.JobDepartments.Clear(); + foreach (var department in departments) + { + id.JobDepartments.Add(department); + } + + Dirty(uid, id); + + return true; + } + /// /// Attempts to change the full name of a card. /// Returns true/false. diff --git a/Content.Shared/Implants/ChameleonControllerImplantComponent.cs b/Content.Shared/Implants/ChameleonControllerImplantComponent.cs new file mode 100644 index 0000000000..d1874b6985 --- /dev/null +++ b/Content.Shared/Implants/ChameleonControllerImplantComponent.cs @@ -0,0 +1,58 @@ +using Content.Shared.Actions; +using Content.Shared.Inventory; +using Content.Shared.Preferences.Loadouts; +using Content.Shared.Roles; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Implants; + +/// +/// Will allow anyone implanted with the implant to have more control over their chameleon clothing and items. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ChameleonControllerImplantComponent : Component; + +/// +/// This is sent when someone clicks on the hud icon and will open the menu. +/// +public sealed partial class ChameleonControllerOpenMenuEvent : InstantActionEvent; + +[Serializable, NetSerializable] +public enum ChameleonControllerKey : byte +{ + Key, +} + +[Serializable, NetSerializable] +public sealed class ChameleonControllerBuiState : BoundUserInterfaceState; + +/// +/// Triggered when the user clicks on a job in the menu. +/// +[Serializable, NetSerializable] +public sealed class ChameleonControllerSelectedOutfitMessage(ProtoId selectedOutfit) : BoundUserInterfaceMessage +{ + public readonly ProtoId SelectedChameleonOutfit = selectedOutfit; +} + +/// +/// This event is raised on clothing when the chameleon controller wants it to change sprite based off selecting an +/// outfit. +/// +/// The outfit being switched to. +/// The users custom loadout for the chameleon outfits job. +/// The default loadout for the chameleon outfits job. +/// The starting gear of the chameleon outfits job. +[ByRefEvent] +public record struct ChameleonControllerOutfitSelectedEvent( + ChameleonOutfitPrototype ChameleonOutfit, + RoleLoadout? CustomRoleLoadout, + RoleLoadout? DefaultRoleLoadout, + StartingGearPrototype? JobStartingGearPrototype, + StartingGearPrototype? StartingGearPrototype +) : IInventoryRelayEvent +{ + SlotFlags IInventoryRelayEvent.TargetSlots => SlotFlags.WITHOUT_POCKET; +} diff --git a/Content.Shared/Implants/ChameleonOutfitPrototype.cs b/Content.Shared/Implants/ChameleonOutfitPrototype.cs new file mode 100644 index 0000000000..59218a14a9 --- /dev/null +++ b/Content.Shared/Implants/ChameleonOutfitPrototype.cs @@ -0,0 +1,64 @@ +using Content.Shared.Roles; +using Content.Shared.StatusIcon; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Implants; + +/// +/// A chameleon clothing outfit. Used for the chameleon controller jobs! Has various fields to help describe a full +/// job - all the fields are optional and override each other if necessary so you should fill out the maximum amount +/// that make sense for the best outcome. +/// +[Prototype] +public sealed partial class ChameleonOutfitPrototype : IPrototype +{ + /// + [ViewVariables, IdDataField] + public string ID { get; private set; } = string.Empty; + + /// + /// Job this outfit is based off of. Will use various things (job icon, job name, loadout etc...) for the outfit. + /// This has the lowest priority for clothing if the user has no custom loadout, but highest if they do. + /// + [DataField] + public ProtoId? Job; + + /// + /// Name of the outfit. This will be used for varous things like the chameleon controller UI and the agent IDs job + /// name. + /// + [DataField] + public LocId? Name; + + /// + /// This name is only used in the chameleon controller UI. + /// + [DataField] + public LocId? LoadoutName; + + /// + /// Generic staring gear. Sometimes outfits don't have jobs but do have starting gear (E.g. Cluwne). + /// + [DataField] + public ProtoId? StartingGear; + + /// + /// Icon for the outfit - used for stuff like the UI or agent ID. + /// + [DataField] + public ProtoId? Icon; + + [DataField] + public List>? Departments; + + [DataField] + public bool HasMindShield; + + /// + /// Custom equipment for this specific chameleon outfit. If your making a new outfit that's just for the controller + /// use this! It can be mixed with the rest of the fields though, it just takes highest priority right under + /// user specified loadouts. + /// + [DataField] + public Dictionary Equipment { get; set; } = new(); +} diff --git a/Content.Shared/Implants/SharedChameleonControllerSystem.cs b/Content.Shared/Implants/SharedChameleonControllerSystem.cs new file mode 100644 index 0000000000..26df60e8cc --- /dev/null +++ b/Content.Shared/Implants/SharedChameleonControllerSystem.cs @@ -0,0 +1,28 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Implants; + +public abstract partial class SharedChameleonControllerSystem : EntitySystem +{ + [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OpenUI); + } + + private void OpenUI(ChameleonControllerOpenMenuEvent ev) + { + var implant = ev.Action.Comp.Container; + + if (!HasComp(implant)) + return; + + if (!_uiSystem.HasUi(implant.Value, ChameleonControllerKey.Key)) + return; + + _uiSystem.OpenUi(implant.Value, ChameleonControllerKey.Key, ev.Performer); + } +} diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs index f3ab87be38..55adadc4ed 100644 --- a/Content.Shared/Inventory/InventorySystem.Relay.cs +++ b/Content.Shared/Inventory/InventorySystem.Relay.cs @@ -12,6 +12,7 @@ using Content.Shared.Explosion; using Content.Shared.Eye.Blinding.Systems; using Content.Shared.Gravity; using Content.Shared.IdentityManagement.Components; +using Content.Shared.Implants; using Content.Shared.Inventory.Events; using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; @@ -51,6 +52,7 @@ public partial class InventorySystem SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); + SubscribeLocalEvent(RelayInventoryEvent); // by-ref events SubscribeLocalEvent(RefRelayInventoryEvent); diff --git a/Content.Shared/Mindshield/FakeMindShield/SharedFakeMindshieldSystem.cs b/Content.Shared/Mindshield/FakeMindShield/SharedFakeMindshieldSystem.cs index 0a7c974200..c82f2b2863 100644 --- a/Content.Shared/Mindshield/FakeMindShield/SharedFakeMindshieldSystem.cs +++ b/Content.Shared/Mindshield/FakeMindShield/SharedFakeMindshieldSystem.cs @@ -1,14 +1,27 @@ using Content.Shared.Actions; +using Content.Shared.Actions.Components; +using Content.Shared.Implants; using Content.Shared.Mindshield.Components; +using Content.Shared.Tag; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; namespace Content.Shared.Mindshield.FakeMindShield; public sealed class SharedFakeMindShieldSystem : EntitySystem { + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly TagSystem _tag = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + // This tag should be placed on the fake mindshield action so there is a way to easily identify it. + private static readonly ProtoId FakeMindShieldImplantTag = "FakeMindShieldImplant"; + public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnToggleMindshield); + SubscribeLocalEvent(OnChameleonControllerOutfitSelected); } private void OnToggleMindshield(EntityUid uid, FakeMindShieldComponent comp, FakeMindShieldToggleEvent toggleEvent) @@ -16,6 +29,48 @@ public sealed class SharedFakeMindShieldSystem : EntitySystem comp.IsEnabled = !comp.IsEnabled; Dirty(uid, comp); } + + private void OnChameleonControllerOutfitSelected(EntityUid uid, FakeMindShieldComponent component, ChameleonControllerOutfitSelectedEvent args) + { + if (component.IsEnabled == args.ChameleonOutfit.HasMindShield) + return; + + // This assumes there is only one fake mindshield action per entity (This is currently enforced) + if (!TryComp(uid, out var actionsComp)) + return; + + // In case the fake mindshield ever doesn't have an action. + var actionFound = false; + + foreach (var action in actionsComp.Actions) + { + if (!_tag.HasTag(action, FakeMindShieldImplantTag)) + continue; + + if (!TryComp(action, out var actionComp)) + continue; + + actionFound = true; + + if (_actions.IsCooldownActive(actionComp, _timing.CurTime)) + continue; + + component.IsEnabled = args.ChameleonOutfit.HasMindShield; + Dirty(uid, component); + + if (actionComp.UseDelay != null) + _actions.SetCooldown(action, actionComp.UseDelay.Value); + + return; + } + + // If they don't have the action for some reason, still set it correctly. + if (!actionFound) + { + component.IsEnabled = args.ChameleonOutfit.HasMindShield; + Dirty(uid, component); + } + } } public sealed partial class FakeMindShieldToggleEvent : InstantActionEvent; diff --git a/Content.Shared/Roles/Jobs/SharedJobSystem.cs b/Content.Shared/Roles/Jobs/SharedJobSystem.cs index 8a4733c834..12d673feda 100644 --- a/Content.Shared/Roles/Jobs/SharedJobSystem.cs +++ b/Content.Shared/Roles/Jobs/SharedJobSystem.cs @@ -100,6 +100,45 @@ public abstract class SharedJobSystem : EntitySystem return false; } + /// + /// Tries to get all the departments for a given job. Will return an empty list if none are found. + /// + public bool TryGetAllDepartments(string jobProto, out List departmentPrototypes) + { + // not sorting it since there should only be 1 primary department for a job. + // this is enforced by the job tests. + var departmentProtos = _prototypes.EnumeratePrototypes(); + departmentPrototypes = new List(); + var found = false; + + foreach (var department in departmentProtos) + { + if (department.Roles.Contains(jobProto)) + { + departmentPrototypes.Add(department); + found = true; + } + } + + return found; + } + + /// + /// Try to get the lowest weighted department for the given job. If the job has no departments will return null. + /// + public bool TryGetLowestWeightDepartment(string jobProto, [NotNullWhen(true)] out DepartmentPrototype? departmentPrototype) + { + departmentPrototype = null; + + if (!TryGetAllDepartments(jobProto, out var departmentPrototypes) || departmentPrototypes.Count == 0) + return false; + + departmentPrototypes.Sort((x, y) => y.Weight.CompareTo(x.Weight)); + + departmentPrototype = departmentPrototypes[0]; + return true; + } + public bool MindHasJobWithId(EntityUid? mindId, string prototypeId) { diff --git a/Content.Shared/Station/SharedStationSpawningSystem.cs b/Content.Shared/Station/SharedStationSpawningSystem.cs index dc14366717..389f696db2 100644 --- a/Content.Shared/Station/SharedStationSpawningSystem.cs +++ b/Content.Shared/Station/SharedStationSpawningSystem.cs @@ -179,4 +179,34 @@ public abstract class SharedStationSpawningSystem : EntitySystem RaiseLocalEvent(entity, ref ev); } } + + /// + /// Gets all the gear for a given slot when passed a loadout. + /// + /// The loadout to look through. + /// The slot that you want the clothing for. + /// + /// If there is a value for the given slot, it will return the proto id for that slot. + /// If nothing was found, will return null + /// + public string? GetGearForSlot(RoleLoadout? loadout, string slot) + { + if (loadout == null) + return null; + + foreach (var group in loadout.SelectedLoadouts) + { + foreach (var items in group.Value) + { + if (!PrototypeManager.TryIndex(items.Prototype, out var loadoutPrototype)) + return null; + + var gear = ((IEquipmentLoadout) loadoutPrototype).GetGear(slot); + if (gear != string.Empty) + return gear; + } + } + + return null; + } } diff --git a/Resources/Locale/en-US/chameleon-outfits/chameleon-outfits.ftl b/Resources/Locale/en-US/chameleon-outfits/chameleon-outfits.ftl new file mode 100644 index 0000000000..f6ffe376c4 --- /dev/null +++ b/Resources/Locale/en-US/chameleon-outfits/chameleon-outfits.ftl @@ -0,0 +1 @@ +chameleon-outfit-sus-name = Sus diff --git a/Resources/Locale/en-US/implant/chameleon-controller.ftl b/Resources/Locale/en-US/implant/chameleon-controller.ftl new file mode 100644 index 0000000000..d7e3d1484a --- /dev/null +++ b/Resources/Locale/en-US/implant/chameleon-controller.ftl @@ -0,0 +1 @@ +chameleon-controller-ui-window-name = Chameleon controls diff --git a/Resources/Locale/en-US/job/department.ftl b/Resources/Locale/en-US/job/department.ftl index c77c1fd572..8711b3f118 100644 --- a/Resources/Locale/en-US/job/department.ftl +++ b/Resources/Locale/en-US/job/department.ftl @@ -8,3 +8,5 @@ department-Security = Security department-Science = Science department-Silicon = Silicon department-Specific = Station specific + +department-Unknown = Unknown diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index 945070dea0..f276c295d9 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -382,6 +382,9 @@ useDelay: 1 - type: InstantAction event: !type:FakeMindShieldToggleEvent + - type: Tag + tags: + - FakeMindShieldImplant - type: entity parent: BaseToggleAction @@ -395,3 +398,15 @@ state: icon-siren useDelay: 1 itemIconStyle: BigAction + +- type: entity + id: ActionChameleonController + name: Control clothing + description: Change your entire outfit fast! + components: + - type: Action + priority: -20 + icon: { sprite: Actions/Implants/implants.rsi, state: chameleon } + itemIconStyle: BigAction + - type: InstantAction + event: !type:ChameleonControllerOpenMenuEvent diff --git a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml index 7bf804b5e5..56bffb73ec 100644 --- a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml +++ b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml @@ -211,7 +211,7 @@ - id: ClothingEyesChameleon - id: ClothingHeadsetChameleon - id: ClothingShoesChameleon - - id: BarberScissors + - id: ChameleonControllerImplanter - type: entity parent: ClothingBackpackDuffelSyndicateBundle diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml index 3b8ade1dd5..2c4b5fae68 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml @@ -44,6 +44,7 @@ - type: Tag tags: - HudMedical + - WhitelistChameleon - type: entity parent: [ClothingEyesBase, ShowSecurityIcons, BaseSecurityContraband] @@ -58,6 +59,7 @@ - type: Tag tags: - HudSecurity + - WhitelistChameleon - type: entity parent: [ClothingEyesBase, BaseCommandContraband] diff --git a/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml b/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml index eb37027999..d0fe3551df 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml @@ -29,6 +29,7 @@ - Bandana - ClothMade - Recyclable + - WhitelistChameleon - type: entity parent: [ClothingHeadBandBase, ClothingMaskBandBlack] diff --git a/Resources/Prototypes/Entities/Clothing/Neck/medals.yml b/Resources/Prototypes/Entities/Clothing/Neck/medals.yml index 031fcb9988..677727d65d 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/medals.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/medals.yml @@ -12,6 +12,7 @@ - type: Tag tags: - Medal + - WhitelistChameleon - type: entity parent: ClothingNeckBase @@ -28,6 +29,7 @@ - type: Tag tags: - Medal + - WhitelistChameleon - type: entity parent: ClothingNeckBase @@ -42,6 +44,7 @@ - type: Tag tags: - Medal + - WhitelistChameleon - type: entity parent: ClothingNeckBase @@ -56,6 +59,7 @@ - type: Tag tags: - Medal + - WhitelistChameleon - type: entity parent: ClothingNeckBase @@ -70,6 +74,7 @@ - type: Tag tags: - Medal + - WhitelistChameleon - type: entity parent: ClothingNeckBase @@ -84,6 +89,7 @@ - type: Tag tags: - Medal + - WhitelistChameleon - type: entity parent: ClothingNeckBase @@ -98,6 +104,7 @@ - type: Tag tags: - Medal + - WhitelistChameleon - type: entity parent: ClothingNeckBase @@ -114,3 +121,4 @@ - type: Tag tags: - Medal + - WhitelistChameleon diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index 2c73342dbe..9668893b5f 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -665,6 +665,7 @@ - type: Tag tags: - MonkeyWearable + - WhitelistChameleon #Wizard Hardsuit - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml index a4d3403db4..fd466e61fa 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml @@ -31,6 +31,7 @@ - type: Tag tags: - HiViz + - WhitelistChameleon #(Bartender) vest - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Misc/implanters.yml b/Resources/Prototypes/Entities/Objects/Misc/implanters.yml index f853069964..9e89f1c8a7 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/implanters.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/implanters.yml @@ -246,6 +246,14 @@ - type: Implanter implant: DnaScramblerImplant +- type: entity + id: ChameleonControllerImplanter + suffix: chameleon controller + parent: BaseImplantOnlyImplanterSyndi + components: + - type: Implanter + implant: ChameleonControllerImplant + #Nuclear Operative/Special implanters - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml index 13b906bbd7..7ddf4945d0 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml @@ -212,6 +212,23 @@ components: - HumanoidAppearance # syndies cant turn hamlet into a human +- type: entity + categories: [ HideSpawnMenu, Spawner ] + parent: BaseSubdermalImplant + id: ChameleonControllerImplant + name: chameleon controller implant + description: This implant allows you to instantly change the appearance of all worn chameleon clothing. + components: + - type: ChameleonControllerImplant + - type: SubdermalImplant + implantAction: ActionChameleonController + - type: UseDelay + delay: 1 + - type: UserInterface + interfaces: + enum.ChameleonControllerKey.Key: + type: ChameleonControllerBoundUserInterface + #Nuclear Operative/Special Exclusive implants - type: entity diff --git a/Resources/Prototypes/Loadouts/loadouts_chameleon.yml b/Resources/Prototypes/Loadouts/loadouts_chameleon.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Resources/Prototypes/Roles/Antags/ninja.yml b/Resources/Prototypes/Roles/Antags/ninja.yml index 6a9a65bb13..9cacfab581 100644 --- a/Resources/Prototypes/Roles/Antags/ninja.yml +++ b/Resources/Prototypes/Roles/Antags/ninja.yml @@ -33,3 +33,11 @@ - Wirecutter - Welder - Multitool + +- type: chameleonOutfit + id: NinjaChameleonOutfit + name: roles-antag-space-ninja-name + startingGear: SpaceNinjaGear + equipment: + id: PassengerPDA + neck: ClothingNeckGoldmedal diff --git a/Resources/Prototypes/Roles/Antags/nukeops.yml b/Resources/Prototypes/Roles/Antags/nukeops.yml index 8f1094802c..4097e5573c 100644 --- a/Resources/Prototypes/Roles/Antags/nukeops.yml +++ b/Resources/Prototypes/Roles/Antags/nukeops.yml @@ -65,6 +65,15 @@ equipment: pocket2: BaseUplinkRadio40TC +- type: chameleonOutfit + id: NukeopsOutfit + name: roles-antag-nuclear-operative-name + startingGear: SyndicateOperativeGearFullNoUplink + icon: "JobIconSyndicate" + equipment: + head: ClothingHeadHelmetHardsuitSyndie + neck: ClothingNeckScarfStripedSyndieRed + #Nuclear Operative Commander Gear - type: startingGear id: SyndicateCommanderGearFull @@ -75,6 +84,15 @@ inhand: - NukeOpsDeclarationOfWar +- type: chameleonOutfit + id: NukeopsCommanderOutfit + name: roles-antag-nuclear-operative-commander-name + startingGear: SyndicateCommanderGearFull + icon: "JobIconSyndicate" + equipment: + head: ClothingHeadHelmetHardsuitSyndieCommander + neck: ClothingNeckScarfStripedSyndieGreen + #Nuclear Operative Medic Gear - type: startingGear id: SyndicateOperativeMedicFull @@ -97,6 +115,15 @@ - CombatMedipen - DeathAcidifierImplanter +- type: chameleonOutfit + id: NukeopsMedicOutfit + name: roles-antag-nuclear-operative-agent-name + startingGear: SyndicateOperativeMedicFull + icon: "JobIconSyndicate" + equipment: + head: ClothingHeadHelmetHardsuitSyndieMedic + neck: ClothingNeckScarfStripedLightBlue + #Lone Operative Gear - type: startingGear id: SyndicateLoneOperativeGearFull diff --git a/Resources/Prototypes/Roles/Jobs/Cargo/cargo_technician.yml b/Resources/Prototypes/Roles/Jobs/Cargo/cargo_technician.yml index cd71ab05b5..ae64cb438a 100644 --- a/Resources/Prototypes/Roles/Jobs/Cargo/cargo_technician.yml +++ b/Resources/Prototypes/Roles/Jobs/Cargo/cargo_technician.yml @@ -25,3 +25,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: CargoTechnicianChameleonOutfit + job: CargoTechnician + equipment: + head: ClothingHeadHatCargosoft + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskBreath + outerClothing: ClothingOuterWinterCargo + neck: ClothingNeckScarfStripedBrown + gloves: ClothingHandsGlovesFingerless diff --git a/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml b/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml index e0cbc95690..f2e7a2fb93 100644 --- a/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml +++ b/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml @@ -44,3 +44,15 @@ storage: back: - Flash + +- type: chameleonOutfit + id: QuartermasterChameleonOutfit + job: Quartermaster + hasMindShield: true + equipment: + head: ClothingHeadHatQMsoft + eyes: ClothingEyesGlassesSunglasses + mask: ClothingMaskBreath + outerClothing: ClothingOuterWinterQM + neck: ClothingNeckCloakQm + gloves: ClothingHandsKnuckleDustersQM diff --git a/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml b/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml index 8a1811f0c9..9bab10529b 100644 --- a/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml +++ b/Resources/Prototypes/Roles/Jobs/Cargo/salvage_specialist.yml @@ -25,3 +25,15 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: SalvageSpecialistChameleonOutfit + job: SalvageSpecialist + equipment: + head: ClothingHeadHatCargosoft + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskGasExplorer + outerClothing: ClothingOuterWinterMiner + neck: ClothingNeckScarfStripedBrown + gloves: ClothingHandsGlovesColorBlack + diff --git a/Resources/Prototypes/Roles/Jobs/CentComm/cburn.yml b/Resources/Prototypes/Roles/Jobs/CentComm/cburn.yml index aeabd38e41..2ba54d48b1 100644 --- a/Resources/Prototypes/Roles/Jobs/CentComm/cburn.yml +++ b/Resources/Prototypes/Roles/Jobs/CentComm/cburn.yml @@ -38,3 +38,11 @@ - GrenadeFlashBang - PillAmbuzolPlus - PillAmbuzol + +- type: chameleonOutfit + id: CBURNChameleonOutfit + job: CBURN + hasMindShield: true + equipment: + head: ClothingHeadHelmetCBURN + neck: ClothingNeckScarfStripedBrown diff --git a/Resources/Prototypes/Roles/Jobs/CentComm/deathsquad.yml b/Resources/Prototypes/Roles/Jobs/CentComm/deathsquad.yml index e46c114ef4..3231783fd3 100644 --- a/Resources/Prototypes/Roles/Jobs/CentComm/deathsquad.yml +++ b/Resources/Prototypes/Roles/Jobs/CentComm/deathsquad.yml @@ -45,3 +45,11 @@ - FreedomImplanter inhand: - WeaponPulseRifle + +- type: chameleonOutfit + id: DeathSquadChameleonOutfit + job: DeathSquad + hasMindShield: true + equipment: + head: ClothingHeadHelmetHardsuitDeathsquad + neck: ClothingNeckBronzeheart diff --git a/Resources/Prototypes/Roles/Jobs/CentComm/emergencyresponseteam.yml b/Resources/Prototypes/Roles/Jobs/CentComm/emergencyresponseteam.yml index 2e47f1f864..1423db752a 100644 --- a/Resources/Prototypes/Roles/Jobs/CentComm/emergencyresponseteam.yml +++ b/Resources/Prototypes/Roles/Jobs/CentComm/emergencyresponseteam.yml @@ -91,6 +91,14 @@ - CrowbarRed - MagazineMagnum +- type: chameleonOutfit + id: ERTLeaderChameleonOutfit + job: ERTLeader + hasMindShield: true + equipment: + head: ClothingHeadHelmetHardsuitERTLeader + neck: ClothingNeckBronzeheart + # Chaplain - type: job id: ERTChaplain @@ -175,6 +183,16 @@ - FoodBakedBunHotX - Lighter +- type: chameleonOutfit + id: ERTChaplainChameleonOutfit + job: ERTChaplain + hasMindShield: true + equipment: + head: ClothingHeadHelmetHardsuitERTChaplain + mask: ClothingMaskGasERT + outerClothing: ClothingOuterHardsuitERTChaplain + shoes: ClothingShoesBootsMagAdv + # Engineer - type: job id: ERTEngineer @@ -250,6 +268,14 @@ - SheetSteel - SheetGlass +- type: chameleonOutfit + id: ERTEngineerChameleonOutfit + job: ERTEngineer + hasMindShield: true + equipment: + head: ClothingHeadHelmetHardsuitERTEngineer + neck: ClothingNeckEngineermedal + # Security - type: job id: ERTSecurity @@ -257,7 +283,7 @@ description: job-description-ertsecurity playTimeTracker: JobERTSecurity setPreference: false - startingGear: ERTEngineerGearEVA + startingGear: ERTSecurityGearEVA icon: "JobIconNanotrasen" supervisors: job-supervisors-centcom canBeAntag: false @@ -343,6 +369,14 @@ - CrowbarRed - MagazinePistol +- type: chameleonOutfit + id: ERTSecurityChameleonOutfit + job: ERTSecurity + hasMindShield: true + equipment: + head: ClothingHeadHelmetHardsuitERTSecurity + neck: ClothingNeckSecuritymedal + # Medical - type: job id: ERTMedical @@ -410,6 +444,14 @@ - ChemistryBottleEpinephrine - ChemistryBottleEpinephrine +- type: chameleonOutfit + id: ERTMedicalChameleonOutfit + job: ERTMedical + hasMindShield: true + equipment: + head: ClothingHeadHelmetHardsuitERTMedical + neck: ClothingNeckStethoscope + # Janitor - type: job id: ERTJanitor @@ -472,3 +514,12 @@ - Soap - CrowbarRed - AdvMopItem + +- type: chameleonOutfit + id: ERTJanitorChameleonOutfit + job: ERTJanitor + hasMindShield: true + equipment: + head: ClothingHeadHelmetHardsuitERTJanitor + neck: ClothingNeckScarfStripedPurple + eyes: ClothingEyesGlassesSunglasses diff --git a/Resources/Prototypes/Roles/Jobs/CentComm/official.yml b/Resources/Prototypes/Roles/Jobs/CentComm/official.yml index 10fb00448e..68fc11b679 100644 --- a/Resources/Prototypes/Roles/Jobs/CentComm/official.yml +++ b/Resources/Prototypes/Roles/Jobs/CentComm/official.yml @@ -30,3 +30,12 @@ belt: WeaponPistolN1984 pocket1: BoxFolderBlack pocket2: PenCentcom + + +- type: chameleonOutfit + id: CentralCommandOfficialOutfit + job: CentralCommandOfficial + hasMindShield: true + equipment: + neck: ClothingNeckScarfStripedCentcom + mask: ClothingMaskGasCentcom diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/assistant.yml b/Resources/Prototypes/Roles/Jobs/Civilian/assistant.yml index 5155c8ca00..c1da684db1 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/assistant.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/assistant.yml @@ -17,3 +17,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: PassengerChameleonOutfit + job: Passenger + equipment: + head: ClothingHeadHatWelding + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskGas + neck: ClothingNeckMantle + outerClothing: ClothingOuterWinterCoat + gloves: ClothingHandsGlovesColorYellowBudget diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml b/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml index 3306c41196..8881fb0d41 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/bartender.yml @@ -27,3 +27,15 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: BartenderChameleonOutfit + job: Bartender + equipment: + head: ClothingHeadHatTophat + eyes: ClothingEyesGlassesSunglasses + mask: ClothingMaskBreath + neck: ClothingNeckScarfStripedBlack + outerClothing: ClothingOuterArmorBasicSlim + gloves: ClothingHandsGlovesColorBlack + diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/botanist.yml b/Resources/Prototypes/Roles/Jobs/Civilian/botanist.yml index 47c1ccca02..f5f05bded9 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/botanist.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/botanist.yml @@ -28,3 +28,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: BotanistChameleonOutfit + job: Botanist + equipment: + head: ClothingHeadBandBotany + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskBreath + neck: ClothingNeckScarfStripedGreen + outerClothing: ClothingOuterApronBotanist + gloves: ClothingHandsGlovesLeather diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml b/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml index 1ab77dbae5..e384801cc5 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml @@ -24,3 +24,15 @@ back: - Bible - RubberStampChaplain + +- type: chameleonOutfit + id: ChaplainChameleonOutfit + job: Chaplain + equipment: + head: ClothingHeadHatPlaguedoctor + eyes: ClothingEyesGlasses + mask: ClothingMaskPlague + neck: ClothingNeckStoleChaplain + outerClothing: ClothingOuterPlagueSuit + gloves: ClothingHandsGlovesColorBlack + diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml b/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml index 8ea6dd1acf..fd3941d4e0 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/chef.yml @@ -28,3 +28,15 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: ChefChameleonOutfit + job: Chef + equipment: + head: ClothingHeadHatChef + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskItalianMoustache + neck: ClothingNeckScarfStripedBrown + outerClothing: ClothingOuterJacketChef + gloves: ClothingHandsGlovesColorWhite + shoes: ClothingShoesChef diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml index b8f289e70e..60821cfe76 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml @@ -37,3 +37,13 @@ back: - RubberStampClown - CrayonRainbow + +- type: chameleonOutfit + id: ClownChameleonOutfit + job: Clown + equipment: + head: ClothingHeadHatXmasCrown + eyes: ClothingEyesGlassesCheapSunglasses + neck: ClothingHeadHatFlowerWreath + outerClothing: ClothingOuterClownPriest + gloves: ClothingHandsGlovesColorYellowBudget diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml b/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml index d361348a6e..15a19b6555 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml @@ -35,3 +35,14 @@ head: ClothingHeadHatCatEars ears: ClothingHeadsetService belt: ClothingBeltJanitorFilled + +- type: chameleonOutfit + id: JanitorChameleonOutfit + job: Janitor + equipment: + head: ClothingHeadHatPurplesoft + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskGas + neck: ClothingNeckScarfStripedPurple + outerClothing: ClothingOuterWinterJani + gloves: ClothingHandsGlovesJanitor diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml b/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml index 3cd8258e59..81c8b71050 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml @@ -27,3 +27,14 @@ back: - RubberStampLawyer - BookSpaceLaw + +- type: chameleonOutfit + id: LawyerChameleonOutfit + job: Lawyer + equipment: + head: ClothingHeadHatBowlerHat + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskBreath + neck: ClothingNeckLawyerbadge + outerClothing: ClothingOuterWinterColorBlack + gloves: ClothingHandsGlovesColorBlack diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml b/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml index 61f0ea1d32..080447979f 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml @@ -21,3 +21,14 @@ storage: back: - BookRandom + +- type: chameleonOutfit + id: LibrarianChameleonOutfit + job: Librarian + equipment: + head: ClothingHeadHatCanadaBeanie + eyes: ClothingEyesGlassesJamjar + mask: ClothingMaskGas + neck: ClothingNeckScarfStripedGreen + outerClothing: ClothingOuterWinterColorGreen + gloves: ClothingHandsGlovesColorBlack diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml index 3fb89a719c..293df524e9 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml @@ -45,3 +45,12 @@ state: full - type: InstantAction event: !type:InvisibleWallActionEvent + +- type: chameleonOutfit + id: MimeChameleonOutfit + job: Mime + equipment: + head: ClothingHeadHatMimesoft + eyes: ClothingEyesGlassesCheapSunglasses + neck: ClothingNeckScarfStripedZebra + outerClothing: ClothingOuterWinterMime diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/musician.yml b/Resources/Prototypes/Roles/Jobs/Civilian/musician.yml index b33525d205..04891ab2c6 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/musician.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/musician.yml @@ -24,3 +24,13 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: MusicianChameleonOutfit + job: Musician + equipment: + head: ClothingHeadHatTophat + mask: ClothingMaskBreath + neck: ClothingNeckHeadphones + outerClothing: ClothingOuterWinterMusician + gloves: ClothingHandsGlovesColorBlack diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/service_worker.yml b/Resources/Prototypes/Roles/Jobs/Civilian/service_worker.yml index 9dd79cfabe..f98dac80ed 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/service_worker.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/service_worker.yml @@ -27,3 +27,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: ServiceWorkerChameleonOutfit + job: ServiceWorker + equipment: + head: ClothingHeadHatBowlerHat + eyes: ClothingEyesGlassesSunglasses + mask: ClothingMaskGas + neck: ClothingNeckScarfStripedBrown + outerClothing: ClothingOuterVest + gloves: ClothingHandsGlovesColorBlack diff --git a/Resources/Prototypes/Roles/Jobs/Command/captain.yml b/Resources/Prototypes/Roles/Jobs/Command/captain.yml index 33fc261922..bc7aef6ab0 100644 --- a/Resources/Prototypes/Roles/Jobs/Command/captain.yml +++ b/Resources/Prototypes/Roles/Jobs/Command/captain.yml @@ -46,3 +46,13 @@ back: - Flash # - StationCharter + +- type: chameleonOutfit + id: CaptainChameleonOutfit + job: Captain + hasMindShield: true + equipment: + head: ClothingHeadHatCapcap + eyes: ClothingEyesGlassesCommand + mask: ClothingMaskGasCaptain + neck: ClothingNeckCloakCap diff --git a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml index 5f4691b250..5bdbe47e80 100644 --- a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml +++ b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml @@ -69,3 +69,15 @@ storage: back: - Flash + +- type: chameleonOutfit + id: HeadOfPersonnelChameleonOutfit + job: HeadOfPersonnel + hasMindShield: true + equipment: + head: ClothingHeadHatHopcap + eyes: ClothingEyesHudCommand + mask: ClothingMaskNeckGaiterRed + neck: ClothingNeckCloakHop + outerClothing: ClothingOuterWinterHoP + diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml b/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml index 007b1d1174..5dda67f25d 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/atmospheric_technician.yml @@ -30,3 +30,13 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: AtmosphericTechnicianChameleonOutfit + job: AtmosphericTechnician + equipment: + head: ClothingHeadHelmetAtmosFire + mask: ClothingMaskGasAtmos + neck: ClothingNeckScarfStripedLightBlue + outerClothing: ClothingOuterSuitAtmosFire + gloves: ClothingHandsGlovesColorYellow diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml b/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml index 5550e02840..264e31a3ae 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/chief_engineer.yml @@ -44,3 +44,15 @@ storage: back: - Flash + +- type: chameleonOutfit + id: ChiefEngineerChameleonOutfit + job: ChiefEngineer + hasMindShield: true + equipment: + head: ClothingHeadHatBeretEngineering + mask: ClothingMaskBreath + neck: ClothingNeckCloakCe + outerClothing: ClothingOuterWinterCE + gloves: ClothingHandsGlovesColorYellow + shoes: ClothingShoesBootsMagAdv diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml b/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml index 17a6e67ae2..c67e3067cb 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/station_engineer.yml @@ -26,3 +26,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: StationEngineerChameleonOutfit + job: StationEngineer + equipment: + head: ClothingHeadHatHardhatYellow + mask: ClothingMaskBreath + neck: ClothingNeckScarfStripedOrange + outerClothing: ClothingOuterWinterEngi + gloves: ClothingHandsGlovesColorYellow + shoes: ClothingShoesBootsMag diff --git a/Resources/Prototypes/Roles/Jobs/Engineering/technical_assistant.yml b/Resources/Prototypes/Roles/Jobs/Engineering/technical_assistant.yml index 23ad4ca401..24cef50e1a 100644 --- a/Resources/Prototypes/Roles/Jobs/Engineering/technical_assistant.yml +++ b/Resources/Prototypes/Roles/Jobs/Engineering/technical_assistant.yml @@ -30,3 +30,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: TechnicalAssistantChameleonOutfit + job: TechnicalAssistant + equipment: + head: ClothingHeadHatHardhatOrange + eyes: ClothingEyesGlassesMeson + mask: ClothingMaskBreath + neck: ClothingNeckScarfStripedOrange + outerClothing: ClothingOuterVestHazard + gloves: ClothingHandsGlovesColorYellow diff --git a/Resources/Prototypes/Roles/Jobs/Fun/cluwne.yml b/Resources/Prototypes/Roles/Jobs/Fun/cluwne.yml index a797208c32..7ec68a5d52 100644 --- a/Resources/Prototypes/Roles/Jobs/Fun/cluwne.yml +++ b/Resources/Prototypes/Roles/Jobs/Fun/cluwne.yml @@ -14,3 +14,14 @@ equipment: pocket1: BikeHorn +- type: chameleonOutfit + id: CluwneChameleonOutfit + name: job-title-cluwne + startingGear: CluwneGear + icon: JobIconCluwne + equipment: + head: ClothingHeadHatXmasCrown + eyes: ClothingEyesBlindfold + ears: ClothingHeadsetGrey + neck: ClothingHeadHatFlowerWreath + outerClothing: ClothingOuterClownPriest diff --git a/Resources/Prototypes/Roles/Jobs/Fun/sus.yml b/Resources/Prototypes/Roles/Jobs/Fun/sus.yml new file mode 100644 index 0000000000..818feb82f4 --- /dev/null +++ b/Resources/Prototypes/Roles/Jobs/Fun/sus.yml @@ -0,0 +1,17 @@ +- type: chameleonOutfit + id: SusChameleonOutfit + loadoutName: chameleon-outfit-sus-name + name: job-name-passenger + icon: "JobIconPassenger" + equipment: + head: ClothingHeadHatBeret + eyes: ClothingEyesGlassesSunglasses + ears: ClothingHeadsetGrey + mask: ClothingMaskGas + outerClothing: ClothingOuterVest + jumpsuit: ClothingUniformJumpsuitColorBlack + neck: ClothingNeckScarfStripedRed + back: ClothingBackpack + gloves: ClothingHandsGlovesColorBlack + shoes: ClothingShoesColorBlack + id: PassengerPDA diff --git a/Resources/Prototypes/Roles/Jobs/Fun/wizard_startinggear.yml b/Resources/Prototypes/Roles/Jobs/Fun/wizard_startinggear.yml index d137df195e..e59e08bf79 100644 --- a/Resources/Prototypes/Roles/Jobs/Fun/wizard_startinggear.yml +++ b/Resources/Prototypes/Roles/Jobs/Fun/wizard_startinggear.yml @@ -28,3 +28,13 @@ jumpsuit: ClothingUniformJumpsuitColorPurple head: ClothingHeadHatVioletwizard outerClothing: ClothingOuterWizardViolet + +- type: chameleonOutfit + id: WizardChameleonOutfit + name: roles-antag-wizard-name + startingGear: WizardBlueGear + equipment: + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskBreath + neck: ClothingNeckLGBTPin + gloves: ClothingHandsGlovesColorBlack diff --git a/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml b/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml index 830af18b9b..e14fbd5b84 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/chemist.yml @@ -26,3 +26,13 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: ChemistChameleonOutfit + job: Chemist + equipment: + head: ClothingHeadHatBeretMedic + mask: ClothingMaskSterile + neck: ClothingNeckStethoscope + outerClothing: ClothingOuterCoatLabChem + gloves: ClothingHandsGlovesLatex diff --git a/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml b/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml index 679c3c883a..b6698091df 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/chief_medical_officer.yml @@ -44,3 +44,15 @@ storage: back: - Flash + +- type: chameleonOutfit + id: ChiefMedicalOfficerChameleonOutfit + job: ChiefMedicalOfficer + hasMindShield: true + equipment: + head: ClothingHeadHatBeretCmo + eyes: ClothingEyesHudMedical + mask: ClothingMaskSterile + neck: ClothingCloakCmo + outerClothing: ClothingOuterCoatLabCmo + gloves: ClothingHandsGlovesNitrile diff --git a/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml b/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml index f0f39d156f..4b43df2004 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/medical_doctor.yml @@ -28,3 +28,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: MedicalDoctorChameleonOutfit + job: MedicalDoctor + equipment: + head: ClothingHeadNurseHat + eyes: ClothingEyesHudMedical + mask: ClothingMaskSterile + neck: ClothingNeckStethoscope + outerClothing: ClothingOuterCoatLab + gloves: ClothingHandsGlovesLatex diff --git a/Resources/Prototypes/Roles/Jobs/Medical/medical_intern.yml b/Resources/Prototypes/Roles/Jobs/Medical/medical_intern.yml index f7414d75ab..d313d12d9b 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/medical_intern.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/medical_intern.yml @@ -27,3 +27,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: MedicalInternChameleonOutfit + job: MedicalIntern + equipment: + head: ClothingHeadHatBeretMedic + eyes: ClothingEyesHudMedical + mask: ClothingMaskSterile + neck: ClothingNeckStethoscope + outerClothing: ClothingOuterCoatLabOpened + gloves: ClothingHandsGlovesLatex diff --git a/Resources/Prototypes/Roles/Jobs/Medical/paramedic.yml b/Resources/Prototypes/Roles/Jobs/Medical/paramedic.yml index 22b985e8d7..5526e63f24 100644 --- a/Resources/Prototypes/Roles/Jobs/Medical/paramedic.yml +++ b/Resources/Prototypes/Roles/Jobs/Medical/paramedic.yml @@ -25,3 +25,14 @@ storage: back: - EmergencyRollerBedSpawnFolded + +- type: chameleonOutfit + id: ParamedicChameleonOutfit + job: Paramedic + equipment: + head: ClothingHeadHatParamedicsoft + eyes: ClothingEyesHudMedical + mask: ClothingMaskSterile + neck: ClothingNeckStethoscope + outerClothing: ClothingOuterCoatParamedicWB + gloves: ClothingHandsGlovesLatex diff --git a/Resources/Prototypes/Roles/Jobs/Science/research_assistant.yml b/Resources/Prototypes/Roles/Jobs/Science/research_assistant.yml index 8dba235d89..e824368cb7 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/research_assistant.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/research_assistant.yml @@ -26,3 +26,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: ResearchAssistantChameleonOutfit + job: ResearchAssistant + equipment: + head: ClothingHeadHatCardborg + eyes: ClothingEyesGlasses + mask: ClothingMaskGas + neck: ClothingNeckScarfStripedPurple + outerClothing: ClothingOuterCoatLab + gloves: ClothingHandsGlovesLatex diff --git a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml index bc341907d7..da41d9f3e0 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml @@ -37,3 +37,15 @@ storage: back: - Flash + +- type: chameleonOutfit + id: ResearchDirectorChameleonOutfit + job: ResearchDirector + hasMindShield: true + equipment: + head: ClothingHeadHatBeretRND + eyes: ClothingEyesGlasses + mask: ClothingMaskGas + neck: ClothingNeckCloakRd + outerClothing: ClothingOuterCoatRD + gloves: ClothingHandsGlovesColorPurple diff --git a/Resources/Prototypes/Roles/Jobs/Science/scientist.yml b/Resources/Prototypes/Roles/Jobs/Science/scientist.yml index cefd26c450..e2e31f8dcf 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/scientist.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/scientist.yml @@ -21,3 +21,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: ScientistChameleonOutfit + job: Scientist + equipment: + head: ClothingHeadBandSkull + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskGas + neck: ClothingNeckTieSci + outerClothing: ClothingOuterCoatRnd + gloves: ClothingHandsGlovesLatex diff --git a/Resources/Prototypes/Roles/Jobs/Security/detective.yml b/Resources/Prototypes/Roles/Jobs/Security/detective.yml index 19f14eda95..e5c9fdf2dc 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/detective.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/detective.yml @@ -35,3 +35,13 @@ - Flash - ForensicPad - ForensicScanner + +- type: chameleonOutfit + id: DetectiveChameleonOutfit + job: Detective + hasMindShield: true + equipment: + head: ClothingHeadHatFedoraBrown + mask: ClothingMaskGasSecurity + neck: ClothingNeckTieDet + gloves: ClothingHandsGlovesForensic diff --git a/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml b/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml index edf45ca944..7db7429263 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml @@ -51,3 +51,11 @@ back: - Flash - MagazinePistol + +- type: chameleonOutfit + id: HeadOfSecurityChameleonOutfit + job: HeadOfSecurity + hasMindShield: true + equipment: + mask: ClothingMaskGasSecurity + neck: ClothingNeckCloakHos diff --git a/Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml b/Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml index 260f92b587..cac79f4822 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml @@ -39,3 +39,15 @@ back: - Flash - MagazinePistol + +- type: chameleonOutfit + id: SecurityCadetChameleonOutfit + job: SecurityCadet + hasMindShield: true + equipment: + head: ClothingHeadHelmetBasic + eyes: ClothingEyesHudSecurity + mask: ClothingMaskGasSecurity + neck: ClothingNeckScarfStripedRed + belt: ClothingBeltSecurity + gloves: ClothingHandsGlovesColorBlack diff --git a/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml b/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml index af074c17aa..432c6b0d3c 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/security_officer.yml @@ -32,3 +32,13 @@ back: - Flash - MagazinePistol + +- type: chameleonOutfit + id: SecurityOfficerChameleonOutfit + job: SecurityOfficer + hasMindShield: true + equipment: + head: ClothingHeadHatBeretSecurity + mask: ClothingMaskGasSecurity + neck: Dinkystar + gloves: ClothingHandsGlovesColorBlack diff --git a/Resources/Prototypes/Roles/Jobs/Security/warden.yml b/Resources/Prototypes/Roles/Jobs/Security/warden.yml index 0a49023a44..42964ee134 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/warden.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/warden.yml @@ -39,3 +39,17 @@ back: - Flash - MagazinePistol + +- type: chameleonOutfit + id: WardenChameleonOutfit + job: Warden + hasMindShield: true + equipment: + head: ClothingHeadHatWarden + mask: ClothingMaskGasSecurity + outerClothing: ClothingOuterCoatWarden + jumpsuit: ClothingUniformJumpsuitWarden + neck: Dinkystar + belt: ClothingBeltSecurity + gloves: ClothingHandsGlovesCombat + shoes: ClothingShoesBootsJack diff --git a/Resources/Prototypes/Roles/Jobs/Wildcards/boxer.yml b/Resources/Prototypes/Roles/Jobs/Wildcards/boxer.yml index 8eb28c273e..bcf7d065c4 100644 --- a/Resources/Prototypes/Roles/Jobs/Wildcards/boxer.yml +++ b/Resources/Prototypes/Roles/Jobs/Wildcards/boxer.yml @@ -24,3 +24,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: BoxerChameleonOutfit + job: Boxer + equipment: + head: ClothingHeadHatBlacksoft + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskBreath + outerClothing: ClothingOuterWinterColorGray + jumpsuit: UniformShortsRedWithTop + neck: ClothingNeckScarfStripedRed diff --git a/Resources/Prototypes/Roles/Jobs/Wildcards/psychologist.yml b/Resources/Prototypes/Roles/Jobs/Wildcards/psychologist.yml index 74e45a605b..e43bab3e72 100644 --- a/Resources/Prototypes/Roles/Jobs/Wildcards/psychologist.yml +++ b/Resources/Prototypes/Roles/Jobs/Wildcards/psychologist.yml @@ -21,3 +21,15 @@ storage: back: - RubberStampPsychologist + +- type: chameleonOutfit + id: PsychologistChameleonOutfit + job: Psychologist + equipment: + head: ClothingHeadHatBeretMedic + eyes: ClothingEyesHudMedical + mask: ClothingMaskSterile + outerClothing: ClothingOuterCoatLab + neck: ClothingNeckStethoscope + belt: ClothingBeltMedical + gloves: ClothingHandsGlovesLatex diff --git a/Resources/Prototypes/Roles/Jobs/Wildcards/reporter.yml b/Resources/Prototypes/Roles/Jobs/Wildcards/reporter.yml index d0a35990d7..c3c61acd96 100644 --- a/Resources/Prototypes/Roles/Jobs/Wildcards/reporter.yml +++ b/Resources/Prototypes/Roles/Jobs/Wildcards/reporter.yml @@ -19,3 +19,14 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: ReporterChameleonOutfit + job: Reporter + equipment: + head: ClothingHeadHatFedoraGrey + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskBreath + outerClothing: ClothingOuterCoatTrench + neck: ClothingNeckTieRed + gloves: ClothingHandsGlovesFingerless diff --git a/Resources/Prototypes/Roles/Jobs/Wildcards/zookeeper.yml b/Resources/Prototypes/Roles/Jobs/Wildcards/zookeeper.yml index 879a5a3af4..643e372a2f 100644 --- a/Resources/Prototypes/Roles/Jobs/Wildcards/zookeeper.yml +++ b/Resources/Prototypes/Roles/Jobs/Wildcards/zookeeper.yml @@ -25,3 +25,15 @@ #storage: #back: #- Stuff + +- type: chameleonOutfit + id: ZookeeperChameleonOutfit + job: Zookeeper + equipment: + eyes: ClothingEyesGlassesCheapSunglasses + mask: ClothingMaskBreath + outerClothing: ClothingOuterWinterColorLightBrown + neck: ClothingNeckScarfStripedBrown + belt: ClothingBeltStorageWaistbag + gloves: ClothingHandsGlovesColorBrown + diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 47feb68248..69a4544486 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -932,6 +932,9 @@ - type: Tag id: MimeHappyHonk +- type: Tag + id: FakeMindShieldImplant + - type: Tag id: MindTransferTarget diff --git a/Resources/Textures/Actions/Implants/implants.rsi/chameleon.png b/Resources/Textures/Actions/Implants/implants.rsi/chameleon.png new file mode 100644 index 0000000000000000000000000000000000000000..86734f67904363972ec1bbd11d144631634048fb GIT binary patch literal 871 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!pje4(L`iUdT1k0gQ7S_~VrE{6o}X)of~lV2 z_vY`DfhxA7MtG)qdTKFn06DA-QjDw&j6jwb5KBYZAh&2RGK0mLfNVoXCI&tr9R5`Y+_A4a2C$-vCOFoB(c1t@P|WNg5=0AeOcJ?jF9Ig@~F5MTnD!UR?s zWN86pL3J4#7=UDxm#7^H^80%Rs7}h$#W5tp{p~dWY+*-n!@{K<9JwsH&TH#4Cf&{5d^5GICOvk= z^pfpbPd4%I@i}pB_xt>LGbWU`zf_$6=U&6rmI|qkN+i4T;h9mCPQ4{!^)__sZEA# z>!c+jRKKiM+7}nmDBg3BXYwL}^ZiWra{j?-4P~1(wYDTV2X1(}tKzxb!R1NwG8e_~ zZgD=SsAkus$o{>KVHxWWze%>SKm*NYE%NxiHn?!6!6O-E#S?YR_r>&+^dE5?6p+hS zKdPSGb@ILVoJAoG%gdZ!aCNJnx^Uvx>(iw%tFM2YyXKzWGy|Kk2PNANIP-^JOG)J7 zbbPl&Q?%i-muP7Bcbf(G=Pf!UEEx0a{o<_+wUw`a|E$fjxSA6@B_pHy{ m_osU%FovEmSRUwMY=~bYeI|`-kAVXy#dx~