[feat] Loadout, DeathGasps, EnergyDoubleCraftSystem

This commit is contained in:
rhailrake
2023-05-01 15:05:43 +06:00
committed by Aviu00
parent 3c6093565d
commit a05364f1ac
33 changed files with 878 additions and 70 deletions

View File

@@ -130,6 +130,10 @@ namespace Content.Client.Entry
_prototypeManager.RegisterIgnore("alertLevels");
_prototypeManager.RegisterIgnore("nukeopsRole");
//WD-EDIT
_prototypeManager.RegisterIgnore("loadout");
//WD-EDIT
_componentFactory.GenerateNetIds();
_adminManager.Initialize();
_screenshotHook.Initialize();

View File

@@ -179,7 +179,8 @@ public sealed partial class ChatSystem : SharedChatSystem
ICommonSession? player = null,
string? nameOverride = null,
bool checkRadioPrefix = true,
bool ignoreActionBlocker = false
bool ignoreActionBlocker = false,
bool force = false
)
{
if (HasComp<GhostComponent>(source))
@@ -201,7 +202,7 @@ public sealed partial class ChatSystem : SharedChatSystem
return;
}
if (!CanSendInGame(message, shell, player))
if (!force && !CanSendInGame(message, shell, player))
return;
ignoreActionBlocker = CheckIgnoreSpeechBlocker(source, ignoreActionBlocker);
@@ -233,9 +234,9 @@ public sealed partial class ChatSystem : SharedChatSystem
message = SanitizeInGameICMessage(source, message, out var emoteStr, shouldCapitalize, shouldPunctuate, sanitizeSlang);
// Was there an emote in the message? If so, send it.
if (player != null && emoteStr != message && emoteStr != null)
if (emoteStr != message && emoteStr != null)
{
SendEntityEmote(source, emoteStr, range, nameOverride, ignoreActionBlocker);
SendEntityEmote(source, emoteStr, range, nameOverride, ignoreActionBlocker, force: force);
}
// This can happen if the entire string is sanitized out.
@@ -262,7 +263,7 @@ public sealed partial class ChatSystem : SharedChatSystem
SendEntityWhisper(source, message, range, null, nameOverride, hideLog, ignoreActionBlocker);
break;
case InGameICChatType.Emote:
SendEntityEmote(source, message, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker);
SendEntityEmote(source, message, range, nameOverride, hideLog: hideLog, ignoreActionBlocker: ignoreActionBlocker, force: force);
break;
}
}
@@ -566,7 +567,8 @@ public sealed partial class ChatSystem : SharedChatSystem
bool hideLog = false,
bool checkEmote = true,
bool ignoreActionBlocker = false,
NetUserId? author = null
NetUserId? author = null,
bool force = false
)
{
if (!_actionBlocker.CanEmote(source) && !ignoreActionBlocker)

View File

@@ -0,0 +1,29 @@
using Content.Shared.Roles;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Server.White.Loadout;
[Prototype("loadout")]
public sealed class LoadoutItemPrototype : IPrototype
{
[IdDataFieldAttribute] public string ID { get; } = default!;
[DataField("entity", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string EntityId { get; } = default!;
// WD-Sponsors-Start
[DataField("sponsorOnly")]
public bool SponsorOnly = false;
// WD-Sponsors-End
[DataField("whitelistJobs", customTypeSerializer: typeof(PrototypeIdListSerializer<JobPrototype>))]
public List<string>? WhitelistJobs { get; }
[DataField("blacklistJobs", customTypeSerializer: typeof(PrototypeIdListSerializer<JobPrototype>))]
public List<string>? BlacklistJobs { get; }
[DataField("speciesRestriction")]
public List<string>? SpeciesRestrictions { get; }
}

View File

@@ -0,0 +1,97 @@
using System.Linq;
using Content.Server.White.Sponsors;
using Content.Server.GameTicking;
using Content.Server.Hands.Systems;
using Content.Server.Storage.EntitySystems;
using Content.Shared.Clothing.Components;
using Content.Shared.Inventory;
using Robust.Shared.Prototypes;
namespace Content.Server.White.Loadout;
// NOTE: Full implementation will be in future, now just sponsor items
public sealed class LoadoutSystem : EntitySystem
{
private const string BackpackSlotId = "back";
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly HandsSystem _handsSystem = default!;
[Dependency] private readonly StorageSystem _storageSystem = default!;
[Dependency] private readonly SponsorsManager _sponsorsManager = default!;
public override void Initialize()
{
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnPlayerSpawned);
}
private void OnPlayerSpawned(PlayerSpawnCompleteEvent ev)
{
if (_sponsorsManager.TryGetInfo(ev.Player.UserId, out var sponsor))
{
foreach (var loadoutId in sponsor.AllowedMarkings)
{
// NOTE: Now is easy to not extract method because event give all info we need
if (_prototypeManager.TryIndex<LoadoutItemPrototype>(loadoutId, out var loadout))
{
var isSponsorOnly = loadout.SponsorOnly &&
!sponsor.AllowedMarkings.Contains(loadoutId);
var isWhitelisted = ev.JobId != null &&
loadout.WhitelistJobs != null &&
!loadout.WhitelistJobs.Contains(ev.JobId);
var isBlacklisted = ev.JobId != null &&
loadout.BlacklistJobs != null &&
loadout.BlacklistJobs.Contains(ev.JobId);
var isSpeciesRestricted = loadout.SpeciesRestrictions != null &&
loadout.SpeciesRestrictions.Contains(ev.Profile.Species);
if (isSponsorOnly || isWhitelisted || isBlacklisted || isSpeciesRestricted)
continue;
var entity = Spawn(loadout.EntityId, Transform(ev.Mob).Coordinates);
// Take in hand if not clothes
if (!TryComp<ClothingComponent>(entity, out var clothing))
{
_handsSystem.TryPickup(ev.Mob, entity);
continue;
}
// Automatically search empty slot for clothes to equip
string? firstSlotName = null;
bool isEquiped = false;
foreach (var slot in _inventorySystem.GetSlots(ev.Mob))
{
if (!clothing.Slots.HasFlag(slot.SlotFlags))
continue;
if (firstSlotName == null)
firstSlotName = slot.Name;
if (_inventorySystem.TryGetSlotEntity(ev.Mob, slot.Name, out var _))
continue;
if (_inventorySystem.TryEquip(ev.Mob, entity, slot.Name, true))
{
isEquiped = true;
break;
}
}
if (isEquiped || firstSlotName == null)
continue;
// Force equip to first valid clothes slot
// Get occupied entity -> Insert to backpack -> Equip loadout entity
if (_inventorySystem.TryGetSlotEntity(ev.Mob, firstSlotName, out var slotEntity) &&
_inventorySystem.TryGetSlotEntity(ev.Mob, BackpackSlotId, out var backEntity) &&
_storageSystem.CanInsert(backEntity.Value, slotEntity.Value, out _))
{
_storageSystem.Insert(backEntity.Value, slotEntity.Value);
}
_inventorySystem.TryEquip(ev.Mob, entity, firstSlotName, true);
}
}
}
}
}

View File

@@ -0,0 +1,57 @@
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Robust.Shared.Audio;
namespace Content.Server.White.Other.EnergySword;
public sealed class EnergyDoubleSwordCraftSystem : EntitySystem
{
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DoubleSwordCraftComponent, InteractUsingEvent>(Combine);
}
private const string NeededEnt = "EnergySword";
private const string EnergyDoubleSword = "EnergyDoubleSword";
private void Combine(EntityUid uid, DoubleSwordCraftComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
var user = args.User;
var usedEnt = _entityManager.GetComponent<MetaDataComponent>(args.Used).EntityPrototype!.ID;
var usedTo = _entityManager.GetComponent<MetaDataComponent>(uid).EntityPrototype!.ID;
if (usedTo is EnergyDoubleSword)
return;
if (usedEnt != NeededEnt || usedTo != NeededEnt)
return;
DeleteUsed(args.Used, uid);
SpawnEnergyDoubleSword(user);
}
private void DeleteUsed(EntityUid itemA, EntityUid itemB)
{
_entityManager.DeleteEntity(itemA);
_entityManager.DeleteEntity(itemB);
}
private void SpawnEnergyDoubleSword(EntityUid player)
{
var transform = CompOrNull<TransformComponent>(player)?.Coordinates;
if (transform == null)
return;
var weaponEntity = _entityManager.SpawnEntity(EnergyDoubleSword, transform.Value);
_handsSystem.PickupOrDrop(player, weaponEntity);
}
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server.White.Other.EnergySword;
[RegisterComponent]
public sealed class DoubleSwordCraftComponent : Component
{
}

View File

@@ -0,0 +1,16 @@
using Content.Shared.Actions.ActionTypes;
using Robust.Shared.Utility;
namespace Content.Server.White.Other.Lazy;
[RegisterComponent]
public sealed class EarsSpawnComponent : Component
{
[DataField("summonAction")] public InstantAction SummonAction = new()
{
Icon = new SpriteSpecifier.Texture(new ResPath("Clothing/Head/Hats/witch.rsi/icon.png")),
DisplayName = "summon cat ears",
Description = "meow!",
Event = new SummonActionEarsEvent()
};
}

View File

@@ -0,0 +1,88 @@
using Content.Shared.ActionBlocker;
using Content.Shared.Actions;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Popups;
using Content.Shared.Verbs;
using Robust.Server.GameObjects;
namespace Content.Server.White.Other.Lazy;
public sealed class EarsSpawnSystem : EntitySystem
{
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<EarsSpawnComponent, GetVerbsEvent<AlternativeVerb>>(AddSummonVerb);
SubscribeLocalEvent<EarsSpawnComponent, GetItemActionsEvent>(GetSummonAction);
SubscribeLocalEvent<EarsSpawnComponent, SummonActionEarsEvent>(OnSummon);
}
private const string Ears = "ClothingHeadHatCatEars";
private const string UserNeededKey = "merkkaa";
private void AddSummonVerb(EntityUid uid, EarsSpawnComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanInteract || !args.CanAccess)
return;
AlternativeVerb verb = new()
{
Act = () =>
{
AttemptSummon(component, args.User);
},
Text = Loc.GetString("summon cat ears"),
Priority = 2
};
args.Verbs.Add(verb);
}
private void OnSummon(EntityUid uid, EarsSpawnComponent component, SummonActionEarsEvent args)
{
AttemptSummon(component, args.Performer);
}
private void AttemptSummon(EarsSpawnComponent component, EntityUid user)
{
if (!_blocker.CanInteract(user, component.Owner))
return;
if (TryComp<ActorComponent>(user, out var actorComponent))
{
var userKey = actorComponent.PlayerSession.Name;
if (userKey != UserNeededKey)
{
_popupSystem.PopupEntity("Вы не являетесь потомком кошко-богини.", user, PopupType.Medium);
return;
}
}
SpawnEars(user);
}
private void SpawnEars(EntityUid player)
{
var transform = CompOrNull<TransformComponent>(player)?.Coordinates;
if (transform == null)
return;
var ears = _entityManager.SpawnEntity(Ears, transform.Value);
_handsSystem.PickupOrDrop(player, ears);
}
private static void GetSummonAction(EntityUid uid, EarsSpawnComponent component, GetItemActionsEvent args)
{
args.Actions.Add(component.SummonAction);
}
}
public sealed class SummonActionEarsEvent : InstantActionEvent
{
}

View File

@@ -0,0 +1,98 @@
using Content.Server.Chat.Systems;
using Content.Server.Ghost.Components;
using Content.Shared.Humanoid;
using Content.Shared.Mobs;
using Robust.Shared.Audio;
using Robust.Shared.Random;
namespace Content.Server.White.Other;
public sealed class OnDeath : EntitySystem
{
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
public override void Initialize()
{
SubscribeLocalEvent<HumanoidAppearanceComponent, MobStateChangedEvent>(HandleDeathEvent);
SubscribeLocalEvent<GhostComponent, ComponentInit>(OnGhosted);
}
private readonly Dictionary<EntityUid, IPlayingAudioStream> _playingStreams = new();
private static readonly SoundSpecifier DeathSounds = new SoundCollectionSpecifier("deathSounds");
private static readonly SoundSpecifier HeartSounds = new SoundCollectionSpecifier("heartSounds");
private static readonly string[] DeathGaspMessages =
{
"death-gasp-high",
"death-gasp-medium",
"death-gasp-normal"
};
private void HandleDeathEvent(EntityUid uid, HumanoidAppearanceComponent component, MobStateChangedEvent args)
{
//^.^
switch (args.NewMobState)
{
case MobState.Invalid:
StopPlayingStream(uid);
break;
case MobState.Alive:
StopPlayingStream(uid);
break;
case MobState.Critical:
PlayPlayingStream(uid);
break;
case MobState.Dead:
StopPlayingStream(uid);
var deathGaspMessage = SelectRandomDeathGaspMessage();
var localizedMessage = LocalizeDeathGaspMessage(deathGaspMessage);
SendDeathGaspMessage(uid, localizedMessage);
PlayDeathSound(uid);
break;
}
}
private void PlayPlayingStream(EntityUid uid)
{
if (_playingStreams.TryGetValue(uid, out var currentStream))
{
currentStream.Stop();
}
var newStream = _audio.PlayEntity(HeartSounds, uid, uid, AudioParams.Default.WithLoop(true));
if (newStream != null)
{
_playingStreams[uid] = newStream;
}
}
private void StopPlayingStream(EntityUid uid)
{
if (_playingStreams.TryGetValue(uid, out var currentStream))
{
currentStream.Stop();
_playingStreams.Remove(uid);
}
}
private string SelectRandomDeathGaspMessage()
=> DeathGaspMessages[_random.Next(DeathGaspMessages.Length)];
private string LocalizeDeathGaspMessage(string message)
=> Loc.GetString(message);
private void SendDeathGaspMessage(EntityUid uid, string message)
=> _chat.TrySendInGameICMessage(uid, message, InGameICChatType.Emote, false, force: true);
private void PlayDeathSound(EntityUid uid)
=> _audio.PlayEntity(DeathSounds, uid, uid, AudioParams.Default);
private void OnGhosted(EntityUid uid, GhostComponent component, ComponentInit args)
{
StopPlayingStream(uid);
}
}

View File

@@ -31,3 +31,5 @@ marking-FoxEarsMaury-ears_fox_tip = Градиент
marking-CatTailDouble = Двойной хвост
marking-CatTailDouble-double_tail_cat_back = Первый хвост
marking-CatTailDouble-double_tail_cat_front = Второй хвост
marking-DemonTailWarete = Демонический хвост

View File

@@ -213,70 +213,29 @@
shader: unshaded
- type: entity
name: Double Bladed Energy Sword
name: double energy sword
parent: EnergySword
id: EnergySwordDouble
description: Syndicate Command Interns thought that having one blade on the energy sword was not enough. This can be stored in pockets.
id: EnergyDoubleSword
description: A very dangerous doubled energy sword. Can be stored in pockets when turned off. Makes a lot of noise when used or turned on.
components:
- type: EnergySword
- type: ItemToggle
soundActivate:
path: /Audio/Weapons/ebladeon.ogg
params:
volume: 3
soundDeactivate:
path: /Audio/Weapons/ebladeoff.ogg
params:
volume: 3
- type: ItemToggleMeleeWeapon
activatedSoundOnSwing:
path: /Audio/Weapons/eblademiss.ogg
params:
volume: 3
variation: 0.250
activatedDamage:
- type: Sprite
sprite: Objects/Weapons/Melee/double_esword.rsi
layers:
- state: e_sword
- state: e_sword_blade
visible: false
shader: unshaded
map: [ "blade" ]
- type: Wieldable
- type: IncreaseDamageOnWield
damage:
types:
Slash: 12
Heat: 12
Structural: 15
- type: ItemToggleActiveSound
activeSound:
path: /Audio/Weapons/ebladehum.ogg
params:
volume: 3
- type: ItemToggleDisarmMalus
activatedDisarmMalus: 0.7
- type: Wieldable
- type: MeleeWeapon
wideAnimationRotation: -135
attackRate: 1.5
angle: 100
damage:
types:
Blunt: 4.5
- type: Sprite
sprite: Objects/Weapons/Melee/e_sword_double.rsi
layers:
- state: e_sword_double
- state: e_sword_double_blade
color: "#FFFFFF"
visible: false
shader: unshaded
map: [ "blade" ]
- type: Item
size: Small
sprite: Objects/Weapons/Melee/e_sword_double-inhands.rsi
- type: Reflect
reflectProb: .75
spread: 75
- type: UseDelay
delay: 1
- type: ToggleableLightVisuals
spriteLayer: blade
inhandVisuals:
left:
- state: inhand-left-blade
shader: unshaded
right:
- state: inhand-right-blade
shader: unshaded
Slash: 15
Heat: 13
- type: MeleeWeapon
attackRate: 1
- type: Reflect
enabled: false
energeticChance: 0.7
kineticChance: 0.7
spread: 45

View File

@@ -0,0 +1,13 @@
- type: soundCollection
id: deathSounds
files:
- /White/Audio/Death/death.ogg
- /White/Audio/Death/death.wav
- type: soundCollection
id: heartSounds
files:
- /White/Audio/Heart/heart.ogg
- /White/Audio/Heart/heart2.wav
- /White/Audio/Heart/heart3.ogg
- /White/Audio/Heart/heart4.ogg

View File

@@ -0,0 +1,112 @@
# DOOMMAX
- type: entity
parent: ClothingOuterEVASuitBase
id: ClothingOuterSuitGlamorous
name: glamorous suit
description: An emergency suit in cases of... emergencies. But glamorous.
components:
- type: Sprite
sprite: White/Fluff/DOOMMAX/glamorous.rsi
- type: Clothing
sprite: White/Fluff/DOOMMAX/glamorous.rsi
- type: ClothingSpeedModifier
walkModifier: 0.7
sprintModifier: 0.7
- type: TemperatureProtection
coefficient: 0.7
- type: ToggleableClothing
clothingPrototype: ClothingHeadHelmetEVA
- type: ContainerContainer
containers:
toggleable-clothing: !type:ContainerSlot {}
- type: entity
parent: ClothingOuterHardsuitEVA
id: ClothingOuterHardsuitEVAGLAMOUR
name: скафандр EVA GLAMOUR
description: Улучшеный Скафандр Гламура! Модный, стильный, совершенный! Способен защитить вас от космического вакуума. В этом скафандре все главы будут ваши. На скафандре подписан владелец - Алина Бэккен.
components:
- type: Sprite
sprite: White/Fluff/DOOMMAX/evaglamour.rsi
- type: Clothing
sprite: White/Fluff/DOOMMAX/evaglamour.rsi
- type: ToggleableClothing
clothingPrototype: ClothingHeadHelmetEVAGLAMOUR
- type: ContainerContainer
containers:
toggleable-clothing: !type:ContainerSlot { }
- type: entity
parent: ClothingHeadHelmetEVA
id: ClothingHeadHelmetEVAGLAMOUR
name: шлем EVA GLAMOUR
description: Гламурный вариант шлема EVA.
components:
- type: Sprite
sprite: White/Fluff/DOOMMAX/helmetglamour.rsi
- type: Clothing
sprite: White/Fluff/DOOMMAX/helmetglamour.rsi
# Maury
- type: entity
parent: ClothingUniformJumpsuitChemistry
id: ClothingUniformJumpsuitMauryZ #Should be ClothingUniformJumpsuitMaury but i`m retard and lazy idiot
name: Rupi's chemist uniform
description: Обычно NanoTrasen не позволяет сотрудникам изменять выданную им униформу, но по отношению к Руперту они проявили снисходительность.
components:
- type: Sprite
sprite: White/Fluff/Maury/chemshit.rsi
- type: Clothing
sprite: White/Fluff/Maury/chemshit.rsi
# YouWellLeer
- type: entity
parent: Crowbar
id: Sledgebar
name: Mjolnir
description: Отлично ломает кости ассистентам и клоуну.
components:
- type: Sprite
sprite: White/Fluff/YouWellLeer/sledgebar.rsi
state: icon
netsync: false
- type: Item
sprite: White/Fluff/YouWellLeer/sledgebar.rsi
size: 30
- type: Wieldable
- type: IncreaseDamageOnWield
damage:
types:
Blunt: 10
# merkkaa
- type: entity
parent: Bible
name: няко библия
description: Книга является заметками кошко богини. Её потомки используют эту книгу как Библию.
id: BibleNya
components:
- type: EarsSpawn
- type: Sprite
netsync: false
sprite: White/Fluff/merkkaa/bible.rsi
state: icon
- type: Item
size: 10
sprite: White/Fluff/merkkaa/bible.rsi
- type: PointLight
radius: 2
energy: 2
color: pink
# Warete
- type: entity
parent: ClothingUniformBase
id: WareteJumpskirt
name: репонит
description: Жаростойкая куртка. С предупреждением о возможной взрывоопасности.
components:
- type: Sprite
sprite: White/Fluff/Warete/warete_jumpsuit.rsi
- type: Clothing
sprite: White/Fluff/Warete/warete_jumpsuit.rsi

View File

@@ -0,0 +1,41 @@
# DOOMMAX
- type: loadout
id: SuitGlamorousLoadout
entity: ClothingOuterSuitGlamorous
sponsorOnly: true
blacklistJobs: [Captain, HeadOfPersonnel, ChiefEngineer, ChiefMedicalOfficer, ResearchDirector, HeadOfSecurity, Quartermaster]
- type: loadout
id: ClothingOuterHardsuitEVAGLAMOURsLoadout
entity: ClothingOuterHardsuitEVAGLAMOUR
sponsorOnly: true
whitelistJobs: [Captain, HeadOfPersonnel, ChiefEngineer, ChiefMedicalOfficer, ResearchDirector, HeadOfSecurity, Quartermaster]
# Maury
- type: loadout
id: ClothingUniformJumpsuitMaury #Should be ClothingUniformMauryLoadout but like i said i`m retard
entity: ClothingUniformJumpsuitMauryZ
sponsorOnly: true
# YouWellLeer
- type: loadout
id: SledgebarLoadout
entity: Sledgebar
sponsorOnly: true
# мурка
- type: loadout
id: BibleNyaLoadout
entity: BibleNya
sponsorOnly: true
- type: loadout # WHITEGPT HUETA ДЛЯ КЛОУНОВ И ВЫШЕ
id: WhiteGPTLoadout
entity: PersonalNeuralAI
sponsorOnly: true
# Warete
- type: loadout
id: WareteJumpskirtLoadout
entity: WareteJumpskirt
sponsorOnly: true

View File

@@ -0,0 +1,34 @@
- type: marking
id: CatTailStripes
bodyPart: Tail
markingCategory: Tail
speciesRestriction: [Human]
sponsorOnly: true
sprites:
- sprite: White/Mobs/Customization/cat_parts.rsi
state: tail_cat_wag_stripes_prime
- sprite: White/Mobs/Customization/cat_parts.rsi
state: tail_cat_wag_stripes_second
- type: marking
id: CatTailMaury
bodyPart: Tail
markingCategory: Tail
speciesRestriction: [Human]
sponsorOnly: true
sprites:
- sprite: White/Mobs/Customization/cat_parts.rsi
state: tail_cat_wag_z
- sprite: White/Mobs/Customization/cat_parts.rsi
state: tail_cat_wag_tip
- type: marking
id: CatTailDouble
bodyPart: Tail
markingCategory: Tail
sponsorOnly: true
sprites:
- sprite: White/Mobs/Customization/double_cat.rsi
state: double_tail_cat_back
- sprite: White/Mobs/Customization/double_cat.rsi
state: double_tail_cat_front

View File

@@ -0,0 +1,25 @@
- type: marking
id: FoxEars
bodyPart: HeadTop
markingCategory: HeadTop
speciesRestriction: [Human]
sponsorOnly: true
sprites:
- sprite: White/Mobs/Customization/fox_parts.rsi
state: ears_fox_outer
- sprite: White/Mobs/Customization/fox_parts.rsi
state: ears_fox_inner
- type: marking
id: FoxEarsMaury
bodyPart: HeadTop
markingCategory: HeadTop
speciesRestriction: [Human]
sponsorOnly: true
sprites:
- sprite: White/Mobs/Customization/fox_parts.rsi
state: ears_fox_outer
- sprite: White/Mobs/Customization/fox_parts.rsi
state: ears_fox_inner
- sprite: White/Mobs/Customization/fox_parts.rsi
state: ears_fox_tip

View File

@@ -0,0 +1,19 @@
- type: marking
id: DemonHairWarete
bodyPart: Hair
markingCategory: HeadTop
speciesRestriction: [ Human ]
sponsorOnly: true
sprites:
- sprite: White/Mobs/Customization/warete_hair.rsi
state: hair
- type: marking
id: DemonTailWarete
bodyPart: Tail
markingCategory: Tail
speciesRestriction: [Human]
sponsorOnly: true
sprites:
- sprite: White/Mobs/Customization/demon_tail.rsi
state: tail

View File

@@ -0,0 +1,22 @@
#YouWellLeer
- type: marking
id: WolfEarsLeer
bodyPart: HeadTop
markingCategory: HeadTop
speciesRestriction: [ Human ]
sponsorOnly: true
sprites:
- sprite: White/Mobs/Customization/wolf_parts.rsi
state: wolf_ears_outer
- sprite: White/Mobs/Customization/wolf_parts.rsi
state: wolf_ears_inner
- type: marking
id: WolfTailLeer
bodyPart: Tail
markingCategory: Tail
speciesRestriction: [Human]
sponsorOnly: true
sprites:
- sprite: White/Mobs/Customization/wolf_parts.rsi
state: wolf_tail

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

View File

@@ -0,0 +1,184 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon",
"delays": [
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
]
]
},
{
"name": "e_sword"
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
},
{
"name": "e_sword_blade",
"delays": [
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
]
]
},
{
"name": "inhand-left-blade",
"directions": 4,
"delays": [
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
],
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
],
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
],
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
]
]
},
{
"name": "inhand-right-blade",
"directions": 4,
"delays": [
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
],
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
],
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
],
[
0.15,
0.05,
0.1,
0.1,
0.05,
0.15,
0.15,
0.05,
0.1,
0.1,
0.05,
0.15
]
]
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.