Система ключей (#7)
* new Dev map * добавлена генерация узора ключей раундстартом * каменная стена подгон KREKSa фиксы * add verbs to lock comp * more Loc work * some popups, logic to lock and unlock locks * return old Dev * ability to add locks into doors * check to locked lock, to insert or remove locks * doors examine * key can uses directly to door * really lockable! * lockable crates! * Bruh... Really big update * Key sprites, long wall template * KeyRingComponent * lock entity start * lockpicking! * Shiny 1 * Update keys.yml * Отображение только для держащего в руке * Final --------- Co-authored-by: Tornado Tech <54727692+Tornado-Technology@users.noreply.github.com>
136
Content.Server/CrystallPunk/LockKey/KeyholeGenerationSystem.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
|
||||
using Content.Server.GameTicking.Events;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.CrystallPunk.LockKey;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Server.CrystallPunk.LockKey;
|
||||
|
||||
|
||||
public sealed partial class KeyholeGenerationSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||
[Dependency] private readonly LockSystem _lock = default!;
|
||||
|
||||
private Dictionary<ProtoId<CPLockCategoryPrototype>, List<int>> _roundKeyData = new();
|
||||
|
||||
private const int DepthCompexity = 2;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
|
||||
|
||||
SubscribeLocalEvent<CPLockComponent, MapInitEvent>(OnLockInit);
|
||||
SubscribeLocalEvent<CPKeyComponent, MapInitEvent>(OnKeyInit);
|
||||
|
||||
SubscribeLocalEvent<CPKeyComponent, ExaminedEvent>(OnKeyExamine);
|
||||
}
|
||||
|
||||
#region Init
|
||||
private void OnRoundStart(RoundStartingEvent ev)
|
||||
{
|
||||
_roundKeyData = new();
|
||||
}
|
||||
|
||||
private void OnKeyInit(Entity<CPKeyComponent> keyEnt, ref MapInitEvent args)
|
||||
{
|
||||
if (keyEnt.Comp.AutoGenerateShape != null)
|
||||
{
|
||||
keyEnt.Comp.LockShape = GetKeyLockData(keyEnt.Comp.AutoGenerateShape.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLockInit(Entity<CPLockComponent> lockEnt, ref MapInitEvent args)
|
||||
{
|
||||
if (lockEnt.Comp.AutoGenerateShape != null)
|
||||
{
|
||||
lockEnt.Comp.LockShape = GetKeyLockData(lockEnt.Comp.AutoGenerateShape.Value);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void OnKeyExamine(Entity<CPKeyComponent> key, ref ExaminedEvent args)
|
||||
{
|
||||
var parent = Transform(key).ParentUid;
|
||||
if (parent != args.Examiner)
|
||||
return;
|
||||
|
||||
if (key.Comp.LockShape == null)
|
||||
return;
|
||||
|
||||
var markup = Loc.GetString("cp-lock-examine-key", ("item", MetaData(key).EntityName));
|
||||
markup += " (";
|
||||
foreach (var item in key.Comp.LockShape)
|
||||
{
|
||||
markup += $"{item} ";
|
||||
}
|
||||
markup += ")";
|
||||
args.PushMarkup(markup);
|
||||
}
|
||||
|
||||
private List<int> GetKeyLockData(ProtoId<CPLockCategoryPrototype> category)
|
||||
{
|
||||
if (_roundKeyData.ContainsKey(category))
|
||||
return _roundKeyData[category];
|
||||
else
|
||||
{
|
||||
var newData = GenerateNewUniqueLockData(category);
|
||||
_roundKeyData[category] = newData;
|
||||
return newData;
|
||||
}
|
||||
}
|
||||
|
||||
private List<int> GenerateNewUniqueLockData(ProtoId<CPLockCategoryPrototype> category)
|
||||
{
|
||||
List<int> newKeyData = new List<int>();
|
||||
var categoryData = _proto.Index(category);
|
||||
var ready = false;
|
||||
var iteration = 0;
|
||||
|
||||
while (!ready)
|
||||
{
|
||||
//Generate try
|
||||
newKeyData = new List<int>();
|
||||
for (int i = 0; i < categoryData.Complexity; i++)
|
||||
{
|
||||
newKeyData.Add(_random.Next(-DepthCompexity, DepthCompexity));
|
||||
}
|
||||
|
||||
//Identity Check shitcode
|
||||
// На текущий момент он пытается сгенерировать уникальный код. Если он 100 раз не смог сгенерировать уникальный код, он выдаст последний сгенерированный неуникальный.
|
||||
var unique = true;
|
||||
foreach (var pair in _roundKeyData)
|
||||
{
|
||||
if (newKeyData.SequenceEqual(pair.Value))
|
||||
{
|
||||
unique = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (unique)
|
||||
return newKeyData;
|
||||
else
|
||||
iteration++;
|
||||
|
||||
if (iteration > 100)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
Log.Error("The unique key for CPLockSystem could not be generated!");
|
||||
return newKeyData; //FUCK
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Corvax.CrystallPunk.SpawnMapBiome;
|
||||
namespace Content.Server.CrystallPunk.SpawnMapBiome;
|
||||
|
||||
/// <summary>
|
||||
/// allows you to initialize a planet on a specific map at initialization time.
|
||||
@@ -5,7 +5,7 @@ using Content.Server.Station.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Corvax.CrystallPunk.SpawnMapBiome;
|
||||
namespace Content.Server.CrystallPunk.SpawnMapBiome;
|
||||
public sealed partial class StationBiomeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly BiomeSystem _biome = default!;
|
||||
@@ -3,6 +3,7 @@ using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Construction;
|
||||
using Content.Server.Construction.Components;
|
||||
using Content.Server.CrystallPunk.LockKey;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Destructible;
|
||||
using Content.Shared.Explosion;
|
||||
@@ -36,7 +37,7 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem
|
||||
SubscribeLocalEvent<EntityStorageComponent, EntityUnpausedEvent>(OnEntityUnpausedEvent);
|
||||
SubscribeLocalEvent<EntityStorageComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<EntityStorageComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<EntityStorageComponent, ActivateInWorldEvent>(OnInteract, after: new[] { typeof(LockSystem) });
|
||||
SubscribeLocalEvent<EntityStorageComponent, ActivateInWorldEvent>(OnInteract, after: new[] { typeof(LockSystem), typeof(KeyholeGenerationSystem) });
|
||||
SubscribeLocalEvent<EntityStorageComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
|
||||
SubscribeLocalEvent<EntityStorageComponent, DestructionEventArgs>(OnDestruction);
|
||||
SubscribeLocalEvent<EntityStorageComponent, GetVerbsEvent<InteractionVerb>>(AddToggleOpenVerb);
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.CrystallPunk.LockKey;
|
||||
|
||||
/// <summary>
|
||||
/// A prototype of the lock category. Need a roundstart mapping to ensure that keys and locks will fit together despite randomization.
|
||||
/// </summary>
|
||||
[Prototype("CPLockCategory")]
|
||||
public sealed partial class CPLockCategoryPrototype : IPrototype
|
||||
{
|
||||
[ViewVariables]
|
||||
[IdDataField]
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The number of elements that will be generated for the category.
|
||||
/// </summary>
|
||||
[DataField] public int Complexity = 3;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.CrystallPunk.LockKey;
|
||||
|
||||
/// <summary>
|
||||
/// a key component that can be used to unlock and lock locks from CPLockComponent
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CPKeyComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public List<int>? LockShape = null;
|
||||
|
||||
/// <summary>
|
||||
/// If not null, automatically generates a key for the specified category on initialization. This ensures that the lock will be opened with a key of the same category.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<CPLockCategoryPrototype>? AutoGenerateShape = null;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Content.Shared.CrystallPunk.LockKey;
|
||||
|
||||
/// <summary>
|
||||
/// A component that allows you to track a ring of keys to quickly open and lock doors with the entire bunch.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CPKeyRingComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Content.Shared.CrystallPunk.LockKey;
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.CrystallPunk.LockKey;
|
||||
|
||||
/// <summary>
|
||||
/// A component of a lock that stores its keyhole shape, complexity, and current state.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CPLockComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public List<int>? LockShape = null;
|
||||
|
||||
[DataField]
|
||||
public float LockPickDamageChance = 0.2f;
|
||||
|
||||
/// <summary>
|
||||
/// On which element of the shape sequence the lock is now located. It's necessary for the mechanics of breaking and entering.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int LockpickStatus = 0;
|
||||
|
||||
/// <summary>
|
||||
/// after a lock is broken into, it leaves a description on it that it's been tampered with.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool LockpickeddFailMarkup = false;
|
||||
|
||||
/// <summary>
|
||||
/// If not null, automatically generates a lock for the specified category on initialization. This ensures that the lock will be opened with a key of the same category.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<CPLockCategoryPrototype>? AutoGenerateShape = null;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Content.Shared.CrystallPunk.LockKey;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.CrystallPunk.LockKey;
|
||||
|
||||
/// <summary>
|
||||
/// A component of a lock that stores its keyhole shape, complexity, and current state.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CPLockpickComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public int Health = 3;
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier SuccessSound = new SoundPathSpecifier("/Audio/_CP14/Items/lockpick_use.ogg")
|
||||
{
|
||||
Params = AudioParams.Default
|
||||
.WithVariation(0.05f)
|
||||
.WithVolume(0.5f)
|
||||
};
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier FailSound = new SoundPathSpecifier("/Audio/_CP14/Items/lockpick_fail.ogg")
|
||||
{
|
||||
Params = AudioParams.Default
|
||||
.WithVariation(0.05f)
|
||||
.WithVolume(0.5f)
|
||||
};
|
||||
}
|
||||
334
Content.Shared/CrystallPunk/LockKey/SharedCPLockKeySystem.cs
Normal file
@@ -0,0 +1,334 @@
|
||||
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Serialization;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Storage.EntitySystems;
|
||||
using Content.Shared.Storage;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
|
||||
namespace Content.Shared.CrystallPunk.LockKey;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public sealed class SharedCPLockKeySystem : EntitySystem
|
||||
{
|
||||
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly LockSystem _lock = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
private const int DepthCompexity = 2; //TODO - fix this constant duplication from KeyholeGenerationSystem.cs
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<LockComponent, ContainerIsInsertingAttemptEvent>(OnLockInsertAttempt);
|
||||
|
||||
SubscribeLocalEvent<LockComponent, EntInsertedIntoContainerMessage>(OnLockInserted);
|
||||
SubscribeLocalEvent<LockComponent, EntRemovedFromContainerMessage>(OnLockRemoved);
|
||||
|
||||
SubscribeLocalEvent<CPKeyComponent, AfterInteractEvent>(OnKeyInteract);
|
||||
SubscribeLocalEvent<CPKeyRingComponent, AfterInteractEvent>(OnKeyRingInteract);
|
||||
SubscribeLocalEvent<CPKeyComponent, GetVerbsEvent<UtilityVerb>>(OnKeyToLockVerb);
|
||||
SubscribeLocalEvent<CPLockpickComponent, GetVerbsEvent<UtilityVerb>>(OnLockpickToLockVerb);
|
||||
}
|
||||
private void OnKeyRingInteract(Entity<CPKeyRingComponent> keyring, ref AfterInteractEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!args.CanReach || args.Target is not { Valid: true } target)
|
||||
return;
|
||||
|
||||
if (!TryComp<StorageComponent>(keyring, out var storageComp))
|
||||
return;
|
||||
|
||||
|
||||
if (TryComp<LockComponent>(args.Target, out var lockComp) &&
|
||||
TryGetLockFromSlot(args.Target.Value, out var lockEnt))
|
||||
{
|
||||
|
||||
foreach (var item in storageComp.StoredItems)
|
||||
{
|
||||
if (!TryComp<CPKeyComponent>(item.Key, out var keyComp))
|
||||
continue;
|
||||
|
||||
if (keyComp.LockShape != lockEnt.Value.Comp.LockShape)
|
||||
continue;
|
||||
|
||||
TryUseKeyOnLock(args.User, args.Target.Value, new Entity<CPKeyComponent>(item.Key, keyComp), lockEnt.Value);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-keyring-use-nofit"), args.Target.Value, args.User);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKeyInteract(Entity<CPKeyComponent> key, ref AfterInteractEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!args.CanReach || args.Target is not { Valid: true } target)
|
||||
return;
|
||||
|
||||
if (TryComp<LockComponent>(args.Target, out var lockComp) &&
|
||||
TryGetLockFromSlot(args.Target.Value, out var lockEnt))
|
||||
{
|
||||
TryUseKeyOnLock(args.User, args.Target.Value, key, new Entity<CPLockComponent>(lockEnt.Value.Owner, lockEnt.Value.Comp));
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLockpickToLockVerb(Entity<CPLockpickComponent> lockpick, ref GetVerbsEvent<UtilityVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess)
|
||||
return;
|
||||
|
||||
if (!TryComp<LockComponent>(args.Target, out var lockComp) || !lockComp.Locked)
|
||||
return;
|
||||
|
||||
if (!TryGetLockFromSlot(args.Target, out var lockItem))
|
||||
return;
|
||||
|
||||
if (!TryComp<CPLockComponent>(lockItem, out var lockItemComp))
|
||||
return;
|
||||
|
||||
var target = args.Target;
|
||||
var user = args.User;
|
||||
|
||||
for (int i = DepthCompexity; i >= -DepthCompexity; i--)
|
||||
{
|
||||
var height = i;
|
||||
var verb = new UtilityVerb()
|
||||
{
|
||||
Act = () =>
|
||||
{
|
||||
TryHackDoorElement(user, target, lockpick, lockItemComp, lockComp, height);
|
||||
},
|
||||
Text = Loc.GetString("cp-lock-verb-lockpick-use-text") + $" {height}",
|
||||
Message = Loc.GetString("cp-lock-verb-lockpick-use-message"),
|
||||
Category = VerbCategory.Lockpick,
|
||||
Priority = height,
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryHackDoorElement(EntityUid user, EntityUid target, Entity<CPLockpickComponent> lockpick, CPLockComponent lockEnt, LockComponent lockComp, int height)
|
||||
{
|
||||
if (lockEnt.LockShape == null)
|
||||
return true;
|
||||
|
||||
if (height == lockEnt.LockShape[lockEnt.LockpickStatus]) //Success
|
||||
{
|
||||
_audio.PlayPvs(lockpick.Comp.SuccessSound, target);
|
||||
lockEnt.LockpickStatus++;
|
||||
if (lockEnt.LockpickStatus >= lockEnt.LockShape.Count) // Final success
|
||||
{
|
||||
if (lockComp.Locked)
|
||||
{
|
||||
_lock.TryUnlock(target, user, lockComp);
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-unlock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
lockEnt.LockpickStatus = 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lock.TryLock(target, user, lockComp);
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
lockEnt.LockpickStatus = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-success"), target, user);
|
||||
return true;
|
||||
}
|
||||
else //Fail
|
||||
{
|
||||
_audio.PlayPvs(lockpick.Comp.FailSound, target);
|
||||
if (_random.Prob(lockEnt.LockPickDamageChance)) // Damage lockpick
|
||||
{
|
||||
lockpick.Comp.Health--;
|
||||
if (lockpick.Comp.Health > 0)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-failed-damage", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
} else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-failed-break", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
QueueDel(lockpick);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-failed", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
}
|
||||
lockEnt.LockpickeddFailMarkup = true;
|
||||
lockEnt.LockpickStatus = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKeyToLockVerb(Entity<CPKeyComponent> key, ref GetVerbsEvent<UtilityVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess)
|
||||
return;
|
||||
|
||||
if (!TryComp<LockComponent>(args.Target, out var lockComp))
|
||||
return;
|
||||
|
||||
if (!TryGetLockFromSlot(args.Target, out var lockItem))
|
||||
return;
|
||||
|
||||
if (!TryComp<CPLockComponent>(lockItem, out var lockItemComp))
|
||||
return;
|
||||
|
||||
var target = args.Target;
|
||||
var user = args.User;
|
||||
|
||||
var verb = new UtilityVerb()
|
||||
{
|
||||
Act = () =>
|
||||
{
|
||||
TryUseKeyOnLock(user, target, key, new Entity<CPLockComponent>(target, lockItemComp));
|
||||
},
|
||||
IconEntity = GetNetEntity(key),
|
||||
Text = Loc.GetString(lockComp.Locked ? "cp-lock-verb-use-key-text-open" : "cp-lock-verb-use-key-text-close", ("item", MetaData(args.Target).EntityName)),
|
||||
Message = Loc.GetString("cp-lock-verb-use-key-message", ("item", MetaData(args.Target).EntityName))
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
private void OnLockInsertAttempt(Entity<LockComponent> lockSlot, ref ContainerIsInsertingAttemptEvent args)
|
||||
{
|
||||
if (!lockSlot.Comp.Initialized)
|
||||
return;
|
||||
|
||||
if (args.Container.ID != lockSlot.Comp.LockSlotId)
|
||||
return;
|
||||
|
||||
if (!TryComp<CPLockComponent>(args.EntityUid, out var lockComp))
|
||||
{
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lockComp == null)
|
||||
return;
|
||||
|
||||
//if (lockComp.Locked)
|
||||
//{
|
||||
// _popup.PopupEntity(Loc.GetString(
|
||||
// "cp-lock-lock-insert-fail-locked",
|
||||
// ("lock", MetaData(args.EntityUid).EntityName),
|
||||
// ("target", MetaData(lockSlot).EntityName)), lockSlot);
|
||||
// args.Cancel();
|
||||
//}
|
||||
}
|
||||
|
||||
private void OnLockInserted(Entity<LockComponent> lockSlot, ref EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (!lockSlot.Comp.Initialized)
|
||||
return;
|
||||
|
||||
if (args.Container.ID != lockSlot.Comp.LockSlotId)
|
||||
return;
|
||||
|
||||
if (!TryComp<CPLockComponent>(args.Entity, out var lockComp))
|
||||
return;
|
||||
|
||||
_appearance.SetData(lockSlot, LockSlotVisuals.LockExist, true);
|
||||
}
|
||||
|
||||
private void OnLockRemoved(Entity<LockComponent> lockSlot, ref EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (args.Container.ID != lockSlot.Comp.LockSlotId)
|
||||
return;
|
||||
_appearance.SetData(lockSlot, LockSlotVisuals.LockExist, false);
|
||||
}
|
||||
|
||||
public bool TryGetLockFromSlot(EntityUid uid,
|
||||
[NotNullWhen(true)] out Entity<CPLockComponent>? lockEnt,
|
||||
LockComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, false))
|
||||
{
|
||||
lockEnt = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (component.LockSlotId == null)
|
||||
{
|
||||
lockEnt = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_itemSlots.TryGetSlot(uid, component.LockSlotId, out ItemSlot? slot))
|
||||
{
|
||||
if (TryComp<CPLockComponent>(slot.Item, out var lockComp))
|
||||
{
|
||||
lockEnt = new Entity<CPLockComponent>(slot.Item.Value, lockComp);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lockEnt = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
lockEnt = null;
|
||||
return false;
|
||||
}
|
||||
private bool TryUseKeyOnLock(EntityUid user, EntityUid target, Entity<CPKeyComponent> keyEnt, Entity<CPLockComponent> lockEnt)
|
||||
{
|
||||
if (!TryComp<LockComponent>(target, out var lockComp))
|
||||
return false;
|
||||
|
||||
var keyShape = keyEnt.Comp.LockShape;
|
||||
var lockShape = lockEnt.Comp.LockShape;
|
||||
|
||||
if (keyShape == null || lockShape == null)
|
||||
return false;
|
||||
|
||||
if (keyShape == lockShape)
|
||||
{
|
||||
if (lockComp.Locked)
|
||||
{
|
||||
if(_lock.TryUnlock(target, user))
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-unlock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_lock.TryLock(target, user))
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-key-use-nofit"), lockEnt, user);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum LockSlotVisuals : byte
|
||||
{
|
||||
LockExist
|
||||
}
|
||||
@@ -18,7 +18,7 @@ public sealed partial class LockComponent : Component
|
||||
/// </summary>
|
||||
[DataField("locked"), ViewVariables(VVAccess.ReadWrite)]
|
||||
[AutoNetworkedField]
|
||||
public bool Locked = true;
|
||||
public bool Locked = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the lock is toggled by simply clicking.
|
||||
@@ -71,6 +71,12 @@ public sealed partial class LockComponent : Component
|
||||
[DataField]
|
||||
[AutoNetworkedField]
|
||||
public TimeSpan UnlockTime;
|
||||
|
||||
/// <summary>
|
||||
/// CrystallPunk LockSystem Adapt: we need LockEntity in object, in slotId.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string? LockSlotId = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.CrystallPunk.LockKey;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Doors;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Hands.Components;
|
||||
@@ -26,6 +28,7 @@ public sealed class LockSystem : EntitySystem
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _sharedPopupSystem = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly SharedCPLockKeySystem _lockCP = default!; //CrystallPunk Lock System Adapt
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize()
|
||||
@@ -40,6 +43,7 @@ public sealed class LockSystem : EntitySystem
|
||||
SubscribeLocalEvent<LockComponent, GotEmaggedEvent>(OnEmagged);
|
||||
SubscribeLocalEvent<LockComponent, LockDoAfter>(OnDoAfterLock);
|
||||
SubscribeLocalEvent<LockComponent, UnlockDoAfter>(OnDoAfterUnlock);
|
||||
SubscribeLocalEvent<LockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened); //CrystallPunk Lock System Adapt
|
||||
}
|
||||
|
||||
private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
|
||||
@@ -52,17 +56,28 @@ public sealed class LockSystem : EntitySystem
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
//CrystallPunk LockSystem Adapt
|
||||
|
||||
// Only attempt an unlock by default on Activate
|
||||
if (lockComp.Locked)
|
||||
{
|
||||
TryUnlock(uid, args.User, lockComp);
|
||||
args.Handled = true;
|
||||
}
|
||||
else if (lockComp.LockOnClick)
|
||||
{
|
||||
TryLock(uid, args.User, lockComp);
|
||||
args.Handled = true;
|
||||
}
|
||||
//if (lockComp.Locked)
|
||||
//{
|
||||
// TryUnlock(uid, args.User, lockComp);
|
||||
// args.Handled = true;
|
||||
//}
|
||||
//else if (lockComp.LockOnClick)
|
||||
//{
|
||||
// TryLock(uid, args.User, lockComp);
|
||||
// args.Handled = true;
|
||||
//}
|
||||
|
||||
//CrystallPunk LockSystem Adapt End
|
||||
}
|
||||
private void OnBeforeDoorOpened(EntityUid uid, LockComponent component, BeforeDoorOpenedEvent args)
|
||||
{
|
||||
if (!component.Locked)
|
||||
return;
|
||||
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnStorageOpenAttempt(EntityUid uid, LockComponent component, ref StorageOpenAttemptEvent args)
|
||||
@@ -78,10 +93,22 @@ public sealed class LockSystem : EntitySystem
|
||||
|
||||
private void OnExamined(EntityUid uid, LockComponent lockComp, ExaminedEvent args)
|
||||
{
|
||||
args.PushText(Loc.GetString(lockComp.Locked
|
||||
? "lock-comp-on-examined-is-locked"
|
||||
: "lock-comp-on-examined-is-unlocked",
|
||||
("entityName", Identity.Name(uid, EntityManager))));
|
||||
//CrystallPunk Lock System Adapt Start
|
||||
if (lockComp.LockSlotId != null && _lockCP.TryGetLockFromSlot(uid, out var lockEnt))
|
||||
{
|
||||
args.PushText(Loc.GetString("cp-lock-examine-lock-slot", ("lock", MetaData(lockEnt.Value).EntityName)));
|
||||
|
||||
args.PushMarkup(Loc.GetString(lockComp.Locked
|
||||
? "lock-comp-on-examined-is-locked"
|
||||
: "lock-comp-on-examined-is-unlocked",
|
||||
("entityName", Identity.Name(uid, EntityManager))));
|
||||
if (lockEnt.Value.Comp.LockpickeddFailMarkup)
|
||||
args.PushMarkup(Loc.GetString("cp-lock-examine-lock-lockpicked", ("lock", MetaData(lockEnt.Value).EntityName)));
|
||||
} else
|
||||
{
|
||||
args.PushText(Loc.GetString("cp-lock-examine-lock-null"));
|
||||
}
|
||||
//CrystallPunk Lock System Adapt End
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -226,20 +253,24 @@ public sealed class LockSystem : EntitySystem
|
||||
|
||||
private void AddToggleLockVerb(EntityUid uid, LockComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || !CanToggleLock(uid, args.User))
|
||||
return;
|
||||
//CrystallPunk Lock System Adapt
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
Act = component.Locked ?
|
||||
() => TryUnlock(uid, args.User, component) :
|
||||
() => TryLock(uid, args.User, component),
|
||||
Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock"),
|
||||
Icon = component.Locked ?
|
||||
new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/unlock.svg.192dpi.png")) :
|
||||
new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/lock.svg.192dpi.png")),
|
||||
};
|
||||
args.Verbs.Add(verb);
|
||||
//if (!args.CanAccess || !args.CanInteract || !CanToggleLock(uid, args.User))
|
||||
// return;
|
||||
//
|
||||
//AlternativeVerb verb = new()
|
||||
//{
|
||||
// Act = component.Locked ?
|
||||
// () => TryUnlock(uid, args.User, component) :
|
||||
// () => TryLock(uid, args.User, component),
|
||||
// Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock"),
|
||||
// Icon = component.Locked ?
|
||||
// new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/unlock.svg.192dpi.png")) :
|
||||
// new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/lock.svg.192dpi.png")),
|
||||
//};
|
||||
//args.Verbs.Add(verb);
|
||||
|
||||
//CrystallPunk Lock System Adapt End
|
||||
}
|
||||
|
||||
private void OnEmagged(EntityUid uid, LockComponent component, ref GotEmaggedEvent args)
|
||||
|
||||
@@ -76,6 +76,9 @@ namespace Content.Shared.Verbs
|
||||
public static readonly VerbCategory InstrumentStyle =
|
||||
new("verb-categories-instrument-style", null);
|
||||
|
||||
public static readonly VerbCategory Lockpick =
|
||||
new("verb-categories-lockpick", "/Textures/Interface/VerbIcons/lock.svg.192dpi.png");
|
||||
|
||||
public static readonly VerbCategory ChannelSelect = new("verb-categories-channel-select", null);
|
||||
|
||||
public static readonly VerbCategory SetSensor = new("verb-categories-set-sensor", null);
|
||||
|
||||
14
Resources/Audio/_CP14/Items/attributions.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
- files: ["key_drop.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: 'Kyanite_ of Freesound.org. Mixed from stereo to mono.'
|
||||
source: "https://freesound.org/people/Kyanite_/sounds/432913/"
|
||||
|
||||
- files: ["lockpick_use.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: 'by Fugeni of Freesound.org. Mixed from stereo to mono.'
|
||||
source: "https://freesound.org/people/Fugeni/sounds/416286/"
|
||||
|
||||
- files: ["lockpick_fail.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: 'by SinusPi of Freesound.org. Cropped and mixed from stereo to mono.'
|
||||
source: "https://freesound.org/people/SinusPi/sounds/545044/"
|
||||
BIN
Resources/Audio/_CP14/Items/key_drop.ogg
Normal file
BIN
Resources/Audio/_CP14/Items/lockpick_fail.ogg
Normal file
BIN
Resources/Audio/_CP14/Items/lockpick_use.ogg
Normal file
9
Resources/Locale/ru-RU/lock/lock-component.ftl
Normal file
@@ -0,0 +1,9 @@
|
||||
lock-comp-on-examined-is-locked = [color=#a84032]Он заперт[/color].
|
||||
lock-comp-on-examined-is-unlocked = [color=#32a834]Он открыт[/color].
|
||||
lock-comp-do-lock-success = Вы заблокировали { $entityName }.
|
||||
lock-comp-do-unlock-success = Вы разблокировали { $entityName }.
|
||||
|
||||
## ToggleLockVerb
|
||||
|
||||
toggle-lock-verb-unlock = Разблокировать
|
||||
toggle-lock-verb-lock = Заблокировать
|
||||
29
Resources/Locale/ru-RU/lock/lock-crystall-punk.ftl
Normal file
@@ -0,0 +1,29 @@
|
||||
cp-lock-slot-component-slot-name-default = Замок
|
||||
|
||||
cp-lock-examine-key = Высота зубчиков на ключе выстраивается в следующую последовательность:
|
||||
cp-lock-examine-lock-slot = Здесь висит {$lock}.
|
||||
cp-lock-examine-lock-null = Сюда можно прикрепить замок.
|
||||
cp-lock-examine-lock-lockpicked = [color=#b57c3c]{$lock} выглядит потрепанным, словно в нем кто-то копался.[/color]
|
||||
|
||||
|
||||
cp-lock-verb-use-key-text-open = Открыть {$item}
|
||||
cp-lock-verb-use-key-text-close = Закрыть {$item}
|
||||
cp-lock-verb-use-key-message = Использовать ключ, чтобы попытаться открыть или закрыть {$item}.
|
||||
|
||||
cp-lock-unlock-lock = Вы открыли {$lock}
|
||||
cp-lock-lock-lock = Вы заблокировали {$lock}
|
||||
|
||||
cp-lock-key-use-nofit = Кажется, этот ключ сюда не подходит...
|
||||
cp-lock-keyring-use-nofit = Кажется, ни один из ключей отсюда не подходит...
|
||||
cp-lock-lock-insert-fail-locked = Сначала разблокируйте {$lock}, чтобы повесить его на {$target}
|
||||
cp-lock-lock-remove-fail-locked = Сначала разблокируйте {$lock}, чтобы снять его с {$target}
|
||||
cp-lock-target-use-failed-locked = {$target} не открывается
|
||||
|
||||
cp-lock-verb-lockpick-use-text = Имитировать:
|
||||
cp-lock-verb-lockpick-use-message = Попытаться имитировать элемент формы ключа.
|
||||
verb-categories-lockpick = Взлом
|
||||
|
||||
cp-lock-lockpick-success = Что-то в замке сдвигается...
|
||||
cp-lock-lockpick-failed = {$lock} с громким щелчком встает на место.
|
||||
cp-lock-lockpick-failed-damage = {$lock} с громким щелчком встает на место, надломив отмчычку.
|
||||
cp-lock-lockpick-failed-break = {$lock} с громким щелчком встает на место, ломая вашу отмычку.
|
||||
@@ -394,25 +394,25 @@ entities:
|
||||
- type: DayCycle
|
||||
timeEntries:
|
||||
- startColor: "#754a4a" #Рассвет
|
||||
duration: 10
|
||||
duration: 30
|
||||
isNight: false
|
||||
- startColor: "#e0ba87" #Полдень
|
||||
duration: 10
|
||||
duration: 30
|
||||
isNight: false
|
||||
- startColor: "#bfeeff" #Полдень
|
||||
duration: 10
|
||||
duration: 30
|
||||
isNight: false
|
||||
- startColor: "#385163" #Вечер
|
||||
duration: 10
|
||||
duration: 30
|
||||
isNight: true
|
||||
- startColor: "#060d12" #Ночь
|
||||
duration: 10
|
||||
duration: 30
|
||||
isNight: true
|
||||
- startColor: "#000000" #Ночь
|
||||
duration: 10
|
||||
duration: 30
|
||||
isNight: true
|
||||
- startColor: "#120906" #Ночь
|
||||
duration: 10
|
||||
duration: 30
|
||||
isNight: false
|
||||
- proto: AirAlarm
|
||||
entities:
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
- type: entity
|
||||
parent: BaseMaterialDoorNavMap
|
||||
id: CPBaseWoodDoor
|
||||
name: деревянная дверь
|
||||
description: Не самая прочная конструкция, но это лучше чем ничего.
|
||||
suffix: Без замка
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Structures/Doors/MineralDoors/wood_door.rsi
|
||||
layers:
|
||||
- state: closed
|
||||
map: ["enum.DoorVisualLayers.Base"]
|
||||
- type: Door
|
||||
bumpOpen: false
|
||||
clickOpen: true
|
||||
closeTimeOne: 0.2
|
||||
closeTimeTwo: 0.6
|
||||
openTimeOne: 0.6
|
||||
openTimeTwo: 0.2
|
||||
openSound:
|
||||
path: /Audio/Effects/door_open.ogg
|
||||
closeSound:
|
||||
path: /Audio/Effects/door_close.ogg
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Wood
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 100
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- type: Lock
|
||||
locked: true
|
||||
lockSlotId: lock_slot
|
||||
- type: ItemSlots
|
||||
slots:
|
||||
lock_slot:
|
||||
name: cp-lock-slot-component-slot-name-default
|
||||
disableEject: true
|
||||
insertOnInteract: false
|
||||
ejectOnBreak: true
|
||||
whitelist:
|
||||
components:
|
||||
- CPLock
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
lock_slot: !type:ContainerSlot
|
||||
|
||||
- type: entity
|
||||
parent: CPBaseWoodDoor
|
||||
id: CPWoodDoorTavern
|
||||
suffix: Таверна
|
||||
components:
|
||||
- type: ItemSlots
|
||||
slots:
|
||||
lock_slot:
|
||||
name: cp-lock-slot-component-slot-name-default
|
||||
startingItem: LockTavern
|
||||
disableEject: true
|
||||
insertOnInteract: false
|
||||
ejectOnBreak: true
|
||||
whitelist:
|
||||
components:
|
||||
- CPLock
|
||||
@@ -37,6 +37,20 @@
|
||||
key: CPwallswood
|
||||
base: wood
|
||||
|
||||
- type: entity
|
||||
id: CaveStoneWall
|
||||
name: каменная порода
|
||||
parent: CPBaseWall
|
||||
description: Прочная каменная природная стена. От нее веет пещерным холодом.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: CrystallPunk/Structures/Walls/cave_stone.rsi
|
||||
- type: Icon
|
||||
sprite: CrystallPunk/Structures/Walls/cave_stone.rsi
|
||||
- type: IconSmooth
|
||||
key: CPwallsbrick
|
||||
base: stone
|
||||
|
||||
- type: entity
|
||||
id: StoneRuinFragment
|
||||
parent: BaseRock
|
||||
41
Resources/Prototypes/_CP14/Entities/keyrings.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: BaseKeyRing
|
||||
suffix: Пустое
|
||||
name: кольцо для ключей
|
||||
description: Позволяет комфортно хранить большое количество ключей в одном месте.
|
||||
components:
|
||||
- type: CPKeyRing
|
||||
- type: Sprite
|
||||
sprite: CrystallPunk/Objects/keys.rsi
|
||||
layers:
|
||||
- state: keyring
|
||||
- state: ring-0
|
||||
map: ["enum.StorageFillLayers.Fill"]
|
||||
- type: Appearance
|
||||
- type: StorageFillVisualizer
|
||||
maxFillLevels: 4
|
||||
fillBaseName: ring
|
||||
- type: Storage
|
||||
grid:
|
||||
- 0,0,5,0
|
||||
maxItemSize: Small
|
||||
whitelist:
|
||||
tags:
|
||||
- CPKey
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.StorageUiKey.Key
|
||||
type: StorageBoundUserInterface
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
storagebase: !type:Container
|
||||
|
||||
- type: entity
|
||||
parent: BaseKeyRing
|
||||
id: KeyRingInnkeeper
|
||||
suffix: Трактирщик
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: KeyTavern
|
||||
42
Resources/Prototypes/_CP14/Entities/keys.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: BaseKey
|
||||
abstract: true
|
||||
name: ключ
|
||||
description: Небольшая заковыристая железяка, открывающая определенные замки. Не отдавайте кому попало!
|
||||
components:
|
||||
- type: Tag
|
||||
tags:
|
||||
- CPKey
|
||||
- type: Item
|
||||
size: Tiny
|
||||
- type: Sprite
|
||||
sprite: CrystallPunk/Objects/keys.rsi
|
||||
- type: CPKey
|
||||
autoGenerateShape: Debug
|
||||
- type: EmitSoundOnLand
|
||||
sound:
|
||||
path: /Audio/_CP14/Items/key_drop.ogg
|
||||
params:
|
||||
variation: 0.05
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: BaseLockpick
|
||||
name: отмычка
|
||||
description: Воровской инструмент, при должном умении и сноровке позволяющий взламывать любые замки.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: CrystallPunk/Objects/keys.rsi
|
||||
state: lockpick
|
||||
- type: CPLockpick
|
||||
|
||||
- type: entity
|
||||
parent: BaseKey
|
||||
id: KeyTavern
|
||||
name: ключ от таверны
|
||||
components:
|
||||
- type: Sprite
|
||||
state: key1
|
||||
- type: CPKey
|
||||
autoGenerateShape: Tavern
|
||||
22
Resources/Prototypes/_CP14/Entities/locks.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
abstract: true
|
||||
id: BaseLock
|
||||
name: стальной замок
|
||||
description: Он запирает вещи. И вам потребуется ключ, чтобы открыть их обратно.
|
||||
components:
|
||||
- type: CPLock
|
||||
lockPickDamageChance: 0.2
|
||||
autoGenerateShape: Debug
|
||||
- type: Sprite
|
||||
sprite: CrystallPunk/Objects/keys.rsi
|
||||
layers:
|
||||
- state: lock
|
||||
|
||||
- type: entity
|
||||
parent: BaseLock
|
||||
id: LockTavern
|
||||
name: замок от таверны
|
||||
components:
|
||||
- type: CPLock
|
||||
autoGenerateShape: Tavern
|
||||
@@ -0,0 +1,7 @@
|
||||
- type: CPLockCategory
|
||||
id: Debug
|
||||
complexity: 10
|
||||
|
||||
- type: CPLockCategory
|
||||
id: Tavern
|
||||
complexity: 3
|
||||
2
Resources/Prototypes/_CP14/tags.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
- type: Tag
|
||||
id: CPKey
|
||||
|
Before Width: | Height: | Size: 272 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key1.png
Normal file
|
After Width: | Height: | Size: 259 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key10.png
Normal file
|
After Width: | Height: | Size: 248 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key11.png
Normal file
|
After Width: | Height: | Size: 236 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key12.png
Normal file
|
After Width: | Height: | Size: 235 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key13.png
Normal file
|
After Width: | Height: | Size: 276 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key14.png
Normal file
|
After Width: | Height: | Size: 247 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key15.png
Normal file
|
After Width: | Height: | Size: 251 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key16.png
Normal file
|
After Width: | Height: | Size: 245 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key17.png
Normal file
|
After Width: | Height: | Size: 230 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key18.png
Normal file
|
After Width: | Height: | Size: 261 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key2.png
Normal file
|
After Width: | Height: | Size: 260 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key3.png
Normal file
|
After Width: | Height: | Size: 257 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key4.png
Normal file
|
After Width: | Height: | Size: 263 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key5.png
Normal file
|
After Width: | Height: | Size: 257 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key6.png
Normal file
|
After Width: | Height: | Size: 247 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key7.png
Normal file
|
After Width: | Height: | Size: 254 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key8.png
Normal file
|
After Width: | Height: | Size: 235 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/key9.png
Normal file
|
After Width: | Height: | Size: 249 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/keyring.png
Normal file
|
After Width: | Height: | Size: 225 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/lock.png
Normal file
|
After Width: | Height: | Size: 332 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/lockpick.png
Normal file
|
After Width: | Height: | Size: 255 B |
@@ -8,7 +8,79 @@
|
||||
"copyright": "Created by TheShuEd (Github) for CrystallPunk14",
|
||||
"states": [
|
||||
{
|
||||
"name": "base"
|
||||
"name": "key1"
|
||||
},
|
||||
{
|
||||
"name": "key2"
|
||||
},
|
||||
{
|
||||
"name": "key3"
|
||||
},
|
||||
{
|
||||
"name": "key4"
|
||||
},
|
||||
{
|
||||
"name": "key5"
|
||||
},
|
||||
{
|
||||
"name": "key6"
|
||||
},
|
||||
{
|
||||
"name": "key7"
|
||||
},
|
||||
{
|
||||
"name": "key8"
|
||||
},
|
||||
{
|
||||
"name": "key9"
|
||||
},
|
||||
{
|
||||
"name": "key10"
|
||||
},
|
||||
{
|
||||
"name": "key11"
|
||||
},
|
||||
{
|
||||
"name": "key12"
|
||||
},
|
||||
{
|
||||
"name": "key13"
|
||||
},
|
||||
{
|
||||
"name": "key14"
|
||||
},
|
||||
{
|
||||
"name": "key15"
|
||||
},
|
||||
{
|
||||
"name": "key16"
|
||||
},
|
||||
{
|
||||
"name": "key17"
|
||||
},
|
||||
{
|
||||
"name": "key18"
|
||||
},
|
||||
{
|
||||
"name": "lock"
|
||||
},
|
||||
{
|
||||
"name": "lockpick"
|
||||
},
|
||||
{
|
||||
"name": "keyring"
|
||||
},
|
||||
{
|
||||
"name": "ring-0"
|
||||
},
|
||||
{
|
||||
"name": "ring-1"
|
||||
},
|
||||
{
|
||||
"name": "ring-2"
|
||||
},
|
||||
{
|
||||
"name": "ring-3"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/ring-0.png
Normal file
|
After Width: | Height: | Size: 96 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/ring-1.png
Normal file
|
After Width: | Height: | Size: 167 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/ring-2.png
Normal file
|
After Width: | Height: | Size: 223 B |
BIN
Resources/Textures/CrystallPunk/Objects/keys.rsi/ring-3.png
Normal file
|
After Width: | Height: | Size: 261 B |
|
After Width: | Height: | Size: 213 B |
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 48
|
||||
},
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Created by TheShuEd (Discord) for CrystallPunk14",
|
||||
"states": [
|
||||
{
|
||||
"name": "wood0",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "wood1",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "wood2",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "wood3",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "wood4",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "wood5",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "wood6",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "wood7",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "full"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 457 B |
|
After Width: | Height: | Size: 415 B |
|
After Width: | Height: | Size: 457 B |
|
After Width: | Height: | Size: 415 B |
|
After Width: | Height: | Size: 417 B |
|
After Width: | Height: | Size: 420 B |
|
After Width: | Height: | Size: 417 B |
|
After Width: | Height: | Size: 317 B |
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Created by KREKS (Discord) for CrystallPunk14",
|
||||
"states": [
|
||||
{
|
||||
"name": "stone0",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "stone1",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "stone2",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "stone3",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "stone4",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "stone5",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "stone6",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "stone7",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "full"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 927 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 265 B |