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 <slambamactionman@gmail.com>
This commit is contained in:
151
Content.Server/Implants/ChameleonControllerSystem.cs
Normal file
151
Content.Server/Implants/ChameleonControllerSystem.cs
Normal file
@@ -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<SubdermalImplantComponent, ChameleonControllerSelectedOutfitMessage>(OnSelected);
|
||||
|
||||
SubscribeLocalEvent<ChameleonClothingComponent, InventoryRelayedEvent<ChameleonControllerOutfitSelectedEvent>>(ChameleonControllerOutfitItemSelected);
|
||||
}
|
||||
|
||||
private void OnSelected(Entity<SubdermalImplantComponent> ent, ref ChameleonControllerSelectedOutfitMessage args)
|
||||
{
|
||||
if (!_delay.TryResetDelay(ent.Owner, true) || ent.Comp.ImplantedEntity == null || !HasComp<ChameleonControllerImplantComponent>(ent))
|
||||
return;
|
||||
|
||||
ChangeChameleonClothingToOutfit(ent.Comp.ImplantedEntity.Value, args.SelectedChameleonOutfit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Switches all the chameleon clothing that the implant user is wearing to look like the selected job.
|
||||
/// </summary>
|
||||
private void ChangeChameleonClothingToOutfit(EntityUid user, ProtoId<ChameleonOutfitPrototype> 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<ActorComponent>(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<RoleLoadoutPrototype>(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<ChameleonClothingComponent> ent, ref InventoryRelayedEvent<ChameleonControllerOutfitSelectedEvent> args)
|
||||
{
|
||||
if (!_inventory.TryGetContainingSlot(ent.Owner, out var slot))
|
||||
return;
|
||||
|
||||
_chameleonClothingSystem.SetSelectedPrototype(ent, GetGearForSlot(args, slot.Name), component: ent.Comp);
|
||||
}
|
||||
|
||||
public string? GetGearForSlot(InventoryRelayedEvent<ChameleonControllerOutfitSelectedEvent> ev, string slotName)
|
||||
{
|
||||
return GetGearForSlot(ev.Args.ChameleonOutfit, ev.Args.CustomRoleLoadout, ev.Args.DefaultRoleLoadout, ev.Args.JobStartingGearPrototype, ev.Args.StartingGearPrototype, slotName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the gear for the given slot. The priority is:
|
||||
/// <br/>1.) Custom loadout from the player for the slot.
|
||||
/// <br/>2.) Chameleon outfit slot equipment.
|
||||
/// <br/>3.) Chameleon outfit starting gear equipment.
|
||||
/// <br/>4.) Default job equipment.
|
||||
/// <br/>5.) Staring equipment for that job.
|
||||
/// </summary>
|
||||
/// <returns>The entity (as a protoid) if there is gear for that slot, null if there isn't.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user