Carp wave spawner and dragons as an actual event (#10254)
9
Content.Client/Dragon/DragonRiftComponent.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Content.Shared.Dragon;
|
||||
|
||||
namespace Content.Client.Dragon;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class DragonRiftComponent : SharedDragonRiftComponent
|
||||
{
|
||||
|
||||
}
|
||||
51
Content.Client/Dragon/DragonSystem.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Content.Shared.Dragon;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Client.Dragon;
|
||||
|
||||
public sealed class DragonSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<DragonRiftComponent, ComponentHandleState>(OnRiftHandleState);
|
||||
}
|
||||
|
||||
private void OnRiftHandleState(EntityUid uid, DragonRiftComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not DragonRiftComponentState state)
|
||||
return;
|
||||
|
||||
if (component.State == state.State) return;
|
||||
|
||||
component.State = state.State;
|
||||
TryComp<SpriteComponent>(uid, out var sprite);
|
||||
TryComp<PointLightComponent>(uid, out var light);
|
||||
|
||||
if (sprite == null && light == null)
|
||||
return;
|
||||
|
||||
switch (state.State)
|
||||
{
|
||||
case DragonRiftState.Charging:
|
||||
sprite?.LayerSetColor(0, Color.FromHex("#569fff"));
|
||||
|
||||
if (light != null)
|
||||
light.Color = Color.FromHex("#366db5");
|
||||
break;
|
||||
case DragonRiftState.AlmostFinished:
|
||||
sprite?.LayerSetColor(0, Color.FromHex("#cf4cff"));
|
||||
|
||||
if (light != null)
|
||||
light.Color = Color.FromHex("#9e2fc1");
|
||||
break;
|
||||
case DragonRiftState.Finished:
|
||||
sprite?.LayerSetColor(0, Color.FromHex("#edbc36"));
|
||||
|
||||
if (light != null)
|
||||
light.Color = Color.FromHex("#cbaf20");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Content.Client/Sprite/RandomSpriteSystem.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using Content.Shared.Sprite;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Reflection;
|
||||
|
||||
namespace Content.Client.Sprite;
|
||||
|
||||
public sealed class RandomSpriteSystem : SharedRandomSpriteSystem
|
||||
{
|
||||
[Dependency] private readonly IReflectionManager _reflection = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<RandomSpriteComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, RandomSpriteComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not RandomSpriteColorComponentState state)
|
||||
return;
|
||||
|
||||
if (state.Selected.Equals(component.Selected))
|
||||
return;
|
||||
|
||||
component.Selected.Clear();
|
||||
component.Selected.EnsureCapacity(state.Selected.Count);
|
||||
|
||||
foreach (var layer in state.Selected)
|
||||
{
|
||||
component.Selected.Add(layer.Key, layer.Value);
|
||||
}
|
||||
|
||||
UpdateAppearance(uid, component);
|
||||
}
|
||||
|
||||
private void UpdateAppearance(EntityUid uid, RandomSpriteComponent component, SpriteComponent? sprite = null)
|
||||
{
|
||||
if (!Resolve(uid, ref sprite, false))
|
||||
return;
|
||||
|
||||
foreach (var layer in component.Selected)
|
||||
{
|
||||
object key;
|
||||
if (_reflection.TryParseEnumReference(layer.Key, out var @enum))
|
||||
{
|
||||
key = @enum;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = layer.Key;
|
||||
}
|
||||
|
||||
sprite.LayerSetState(key, layer.Value.State);
|
||||
sprite.LayerSetColor(key, layer.Value.Color ?? Color.White);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,11 +32,42 @@ namespace Content.Server.Dragon
|
||||
[DataField("devourAction")]
|
||||
public EntityTargetAction? DevourAction;
|
||||
|
||||
[DataField("spawnActionId", customTypeSerializer: typeof(PrototypeIdSerializer<InstantActionPrototype>))]
|
||||
public string SpawnActionId = "DragonSpawn";
|
||||
/// <summary>
|
||||
/// If we have active rifts.
|
||||
/// </summary>
|
||||
[ViewVariables, DataField("rifts")]
|
||||
public List<EntityUid> Rifts = new();
|
||||
|
||||
[DataField("spawnAction")]
|
||||
public InstantAction? SpawnAction;
|
||||
public bool Weakened => WeakenedAccumulator > 0f;
|
||||
|
||||
/// <summary>
|
||||
/// When any rift is destroyed how long is the dragon weakened for
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("weakenedDuration")]
|
||||
public float WeakenedDuration = 120f;
|
||||
|
||||
/// <summary>
|
||||
/// Has a rift been destroyed and the dragon in a temporary weakened state?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("weakenedAccumulator")]
|
||||
public float WeakenedAccumulator = 0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("riftAccumulator")]
|
||||
public float RiftAccumulator = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum time the dragon can go without spawning a rift before they die.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("maxAccumulator")] public float RiftMaxAccumulator = 300f;
|
||||
|
||||
/// <summary>
|
||||
/// Spawns a rift which can summon more mobs.
|
||||
/// </summary>
|
||||
[ViewVariables, DataField("spawnRiftAction")]
|
||||
public InstantAction? SpawnRiftAction;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("riftPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string RiftPrototype = "CarpRift";
|
||||
|
||||
/// <summary>
|
||||
/// The amount of time it takes to devour something
|
||||
@@ -48,14 +79,7 @@ namespace Content.Server.Dragon
|
||||
public float StructureDevourTime = 10f;
|
||||
|
||||
[DataField("devourTime")]
|
||||
public float DevourTime = 2f;
|
||||
|
||||
[DataField("spawnCount")] public int SpawnsLeft = 2;
|
||||
|
||||
[DataField("maxSpawnCount")] public int MaxSpawns = 2;
|
||||
|
||||
[DataField("spawnProto", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string? SpawnPrototype = "MobCarpDragon";
|
||||
public float DevourTime = 3f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("soundDeath")]
|
||||
public SoundSpecifier? SoundDeath = new SoundPathSpecifier("/Audio/Animals/space_dragon_roar.ogg");
|
||||
@@ -76,7 +100,7 @@ namespace Content.Server.Dragon
|
||||
public SoundSpecifier? SoundRoar =
|
||||
new SoundPathSpecifier("/Audio/Animals/space_dragon_roar.ogg")
|
||||
{
|
||||
Params = AudioParams.Default.WithVolume(-3f),
|
||||
Params = AudioParams.Default.WithVolume(3f),
|
||||
};
|
||||
|
||||
public CancellationTokenSource? CancelToken;
|
||||
@@ -103,5 +127,5 @@ namespace Content.Server.Dragon
|
||||
|
||||
public sealed class DragonDevourActionEvent : EntityTargetActionEvent {}
|
||||
|
||||
public sealed class DragonSpawnActionEvent : InstantActionEvent {}
|
||||
public sealed class DragonSpawnRiftActionEvent : InstantActionEvent {}
|
||||
}
|
||||
40
Content.Server/Dragon/Components/DragonRiftComponent.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Content.Shared.Dragon;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Dragon;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class DragonRiftComponent : SharedDragonRiftComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Dragon that spawned this rift.
|
||||
/// </summary>
|
||||
[ViewVariables, DataField("dragon")] public EntityUid Dragon;
|
||||
|
||||
/// <summary>
|
||||
/// How long the rift has been active.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("accumulator")]
|
||||
public float Accumulator = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount we can accumulate before becoming impervious.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("maxAccumuluator")] public float MaxAccumulator = 300f;
|
||||
|
||||
/// <summary>
|
||||
/// Accumulation of the spawn timer.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("spawnAccumulator")]
|
||||
public float SpawnAccumulator = 60f;
|
||||
|
||||
/// <summary>
|
||||
/// How long it takes for a new spawn to be added.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("spawnCooldown")]
|
||||
public float SpawnCooldown = 60f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("spawn", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string SpawnPrototype = "MobCarpDragon";
|
||||
}
|
||||
67
Content.Server/Dragon/DragonSystem.Rule.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System.Linq;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.StationEvents.Components;
|
||||
using Content.Shared.Dragon;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Dragon;
|
||||
|
||||
public sealed partial class DragonSystem
|
||||
{
|
||||
public override string Prototype => "Dragon";
|
||||
|
||||
private int RiftsMet(DragonComponent component)
|
||||
{
|
||||
var finished = 0;
|
||||
|
||||
foreach (var rift in component.Rifts)
|
||||
{
|
||||
if (!TryComp<DragonRiftComponent>(rift, out var drift) ||
|
||||
drift.State != DragonRiftState.Finished)
|
||||
continue;
|
||||
|
||||
finished++;
|
||||
}
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
public override void Started()
|
||||
{
|
||||
var spawnLocations = EntityManager.EntityQuery<IMapGridComponent, TransformComponent>().ToList();
|
||||
|
||||
if (spawnLocations.Count == 0)
|
||||
return;
|
||||
|
||||
var location = _random.Pick(spawnLocations);
|
||||
Spawn("MobDragon", location.Item2.MapPosition);
|
||||
}
|
||||
|
||||
public override void Ended()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private void OnRiftRoundEnd(RoundEndTextAppendEvent args)
|
||||
{
|
||||
if (!RuleAdded)
|
||||
return;
|
||||
|
||||
args.AddLine(Loc.GetString("dragon-round-end-summary"));
|
||||
|
||||
foreach (var dragon in EntityQuery<DragonComponent>(true))
|
||||
{
|
||||
var met = RiftsMet(dragon);
|
||||
|
||||
if (TryComp<ActorComponent>(dragon.Owner, out var actor))
|
||||
{
|
||||
args.AddLine(Loc.GetString("dragon-round-end-dragon-player", ("name", dragon.Owner), ("rifts", met), ("player", actor.PlayerSession)));
|
||||
}
|
||||
else
|
||||
{
|
||||
args.AddLine(Loc.GetString("dragon-round-end-dragon", ("name", dragon.Owner), ("rifts", met)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,15 +9,27 @@ using Content.Shared.MobState.Components;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
using System.Threading;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Dragon;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Dragon
|
||||
{
|
||||
public sealed class DragonSystem : EntitySystem
|
||||
public sealed partial class DragonSystem : GameRuleSystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
|
||||
@@ -26,13 +38,200 @@ namespace Content.Server.Dragon
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DragonComponent, ComponentStartup>(OnStartup);
|
||||
SubscribeLocalEvent<DragonComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<DragonComponent, DragonDevourComplete>(OnDragonDevourComplete);
|
||||
SubscribeLocalEvent<DragonComponent, DragonDevourActionEvent>(OnDevourAction);
|
||||
SubscribeLocalEvent<DragonComponent, DragonSpawnActionEvent>(OnDragonSpawnAction);
|
||||
SubscribeLocalEvent<DragonComponent, DragonSpawnRiftActionEvent>(OnDragonRift);
|
||||
SubscribeLocalEvent<DragonComponent, RefreshMovementSpeedModifiersEvent>(OnDragonMove);
|
||||
|
||||
SubscribeLocalEvent<DragonComponent, DragonStructureDevourComplete>(OnDragonStructureDevourComplete);
|
||||
SubscribeLocalEvent<DragonComponent, DragonDevourCancelledEvent>(OnDragonDevourCancelled);
|
||||
SubscribeLocalEvent<DragonComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||
|
||||
SubscribeLocalEvent<DragonRiftComponent, ComponentShutdown>(OnRiftShutdown);
|
||||
SubscribeLocalEvent<DragonRiftComponent, ComponentGetState>(OnRiftGetState);
|
||||
SubscribeLocalEvent<DragonRiftComponent, AnchorStateChangedEvent>(OnAnchorChange);
|
||||
SubscribeLocalEvent<DragonRiftComponent, ExaminedEvent>(OnRiftExamined);
|
||||
|
||||
SubscribeLocalEvent<RoundEndTextAppendEvent>(OnRiftRoundEnd);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var comp in EntityQuery<DragonComponent>())
|
||||
{
|
||||
if (comp.WeakenedAccumulator > 0f)
|
||||
{
|
||||
comp.WeakenedAccumulator -= frameTime;
|
||||
|
||||
// No longer weakened.
|
||||
if (comp.WeakenedAccumulator < 0f)
|
||||
{
|
||||
comp.WeakenedAccumulator = 0f;
|
||||
_movement.RefreshMovementSpeedModifiers(comp.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
// At max rifts
|
||||
if (comp.Rifts.Count >= 3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there's an active rift don't accumulate.
|
||||
if (comp.Rifts.Count > 0)
|
||||
{
|
||||
var lastRift = comp.Rifts[^1];
|
||||
|
||||
if (TryComp<DragonRiftComponent>(lastRift, out var rift) && rift.State != DragonRiftState.Finished)
|
||||
{
|
||||
comp.RiftAccumulator = 0f;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
comp.RiftAccumulator += frameTime;
|
||||
|
||||
// Delete it, naughty dragon!
|
||||
if (comp.RiftAccumulator >= comp.RiftMaxAccumulator)
|
||||
{
|
||||
Roar(comp);
|
||||
QueueDel(comp.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var comp in EntityQuery<DragonRiftComponent>())
|
||||
{
|
||||
if (comp.State != DragonRiftState.Finished && comp.Accumulator >= comp.MaxAccumulator)
|
||||
{
|
||||
// TODO: When we get autocall you can buff if the rift finishes / 3 rifts are up
|
||||
// for now they just keep 3 rifts up.
|
||||
|
||||
comp.Accumulator = comp.MaxAccumulator;
|
||||
RemComp<DamageableComponent>(comp.Owner);
|
||||
comp.State = DragonRiftState.Finished;
|
||||
Dirty(comp);
|
||||
}
|
||||
else
|
||||
{
|
||||
comp.Accumulator += frameTime;
|
||||
}
|
||||
|
||||
comp.SpawnAccumulator += frameTime;
|
||||
|
||||
if (comp.State < DragonRiftState.AlmostFinished && comp.SpawnAccumulator > comp.MaxAccumulator / 2f)
|
||||
{
|
||||
comp.State = DragonRiftState.AlmostFinished;
|
||||
Dirty(comp);
|
||||
var location = Transform(comp.Owner).LocalPosition;
|
||||
|
||||
_chat.DispatchGlobalAnnouncement(Loc.GetString("carp-rift-warning", ("location", location)), playSound: false, colorOverride: Color.Red);
|
||||
_audioSystem.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast());
|
||||
}
|
||||
|
||||
if (comp.SpawnAccumulator > comp.SpawnCooldown)
|
||||
{
|
||||
comp.SpawnAccumulator -= comp.SpawnCooldown;
|
||||
Spawn(comp.SpawnPrototype, Transform(comp.Owner).MapPosition);
|
||||
// TODO: When NPC refactor make it guard the rift.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Rift
|
||||
|
||||
private void OnRiftExamined(EntityUid uid, DragonRiftComponent component, ExaminedEvent args)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("carp-rift-examine", ("percentage", MathF.Round(component.Accumulator / component.MaxAccumulator * 100))));
|
||||
}
|
||||
|
||||
private void OnAnchorChange(EntityUid uid, DragonRiftComponent component, ref AnchorStateChangedEvent args)
|
||||
{
|
||||
if (!args.Anchored && component.State == DragonRiftState.Charging)
|
||||
{
|
||||
QueueDel(uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRiftShutdown(EntityUid uid, DragonRiftComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (TryComp<DragonComponent>(component.Dragon, out var dragon) && !dragon.Weakened)
|
||||
{
|
||||
foreach (var rift in dragon.Rifts)
|
||||
{
|
||||
QueueDel(rift);
|
||||
}
|
||||
|
||||
dragon.Rifts.Clear();
|
||||
|
||||
// We can't predict the rift being destroyed anyway so no point adding weakened to shared.
|
||||
dragon.WeakenedAccumulator = dragon.WeakenedDuration;
|
||||
_movement.RefreshMovementSpeedModifiers(component.Dragon);
|
||||
_popupSystem.PopupEntity(Loc.GetString("carp-rift-destroyed"), component.Dragon, Filter.Entities(component.Dragon));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRiftGetState(EntityUid uid, DragonRiftComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new DragonRiftComponentState()
|
||||
{
|
||||
State = component.State
|
||||
};
|
||||
}
|
||||
|
||||
private void OnDragonMove(EntityUid uid, DragonComponent component, RefreshMovementSpeedModifiersEvent args)
|
||||
{
|
||||
if (component.Weakened)
|
||||
{
|
||||
args.ModifySpeed(0.5f, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDragonRift(EntityUid uid, DragonComponent component, DragonSpawnRiftActionEvent args)
|
||||
{
|
||||
if (component.Weakened)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("carp-rift-weakened"), uid, Filter.Entities(uid));
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.Rifts.Count >= 3)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("carp-rift-max"), uid, Filter.Entities(uid));
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.Rifts.Count > 0 && TryComp<DragonRiftComponent>(component.Rifts[^1], out var rift) && rift.State != DragonRiftState.Finished)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("carp-rift-duplicate"), uid, Filter.Entities(uid));
|
||||
return;
|
||||
}
|
||||
|
||||
var xform = Transform(uid);
|
||||
|
||||
// Have to be on a grid fam
|
||||
if (xform.GridUid == null)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("carp-rift-anchor"), uid, Filter.Entities(uid));
|
||||
return;
|
||||
}
|
||||
|
||||
var carpUid = Spawn(component.RiftPrototype, xform.MapPosition);
|
||||
component.Rifts.Add(carpUid);
|
||||
Comp<DragonRiftComponent>(carpUid).Dragon = uid;
|
||||
_audioSystem.Play("/Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg", Filter.Pvs(carpUid, entityManager: EntityManager), carpUid);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void OnShutdown(EntityUid uid, DragonComponent component, ComponentShutdown args)
|
||||
{
|
||||
foreach (var rift in component.Rifts)
|
||||
{
|
||||
QueueDel(rift);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMobStateChanged(EntityUid uid, DragonComponent component, MobStateChangedEvent args)
|
||||
@@ -59,13 +258,7 @@ namespace Content.Server.Dragon
|
||||
var ichorInjection = new Solution(component.DevourChem, component.DevourHealRate);
|
||||
|
||||
//Humanoid devours allow dragon to get eggs, corpses included
|
||||
if (EntityManager.HasComponent<HumanoidAppearanceComponent>(args.Target))
|
||||
{
|
||||
// Add a spawn for a consumed humanoid
|
||||
component.SpawnsLeft = Math.Min(component.SpawnsLeft + 1, component.MaxSpawns);
|
||||
}
|
||||
//Non-humanoid mobs can only heal dragon for half the normal amount, with no additional spawn tickets
|
||||
else
|
||||
if (!EntityManager.HasComponent<HumanoidAppearanceComponent>(args.Target))
|
||||
{
|
||||
ichorInjection.ScaleSolution(0.5f);
|
||||
}
|
||||
@@ -87,10 +280,14 @@ namespace Content.Server.Dragon
|
||||
_audioSystem.PlayPvs(component.SoundDevour, uid, component.SoundDevour.Params);
|
||||
}
|
||||
|
||||
private void Roar(DragonComponent component)
|
||||
{
|
||||
if (component.SoundRoar != null)
|
||||
_audioSystem.Play(component.SoundRoar, Filter.Pvs(component.Owner, 4f, EntityManager), component.Owner, component.SoundRoar.Params);
|
||||
}
|
||||
|
||||
private void OnStartup(EntityUid uid, DragonComponent component, ComponentStartup args)
|
||||
{
|
||||
component.SpawnsLeft = Math.Min(component.SpawnsLeft, component.MaxSpawns);
|
||||
|
||||
//Dragon doesn't actually chew, since he sends targets right into his stomach.
|
||||
//I did it mom, I added ERP content into upstream. Legally!
|
||||
component.DragonStomach = _containerSystem.EnsureContainer<Container>(uid, "dragon_stomach");
|
||||
@@ -98,11 +295,10 @@ namespace Content.Server.Dragon
|
||||
if (component.DevourAction != null)
|
||||
_actionsSystem.AddAction(uid, component.DevourAction, null);
|
||||
|
||||
if (component.SpawnAction != null)
|
||||
_actionsSystem.AddAction(uid, component.SpawnAction, null);
|
||||
if (component.SpawnRiftAction != null)
|
||||
_actionsSystem.AddAction(uid, component.SpawnRiftAction, null);
|
||||
|
||||
if (component.SoundRoar != null)
|
||||
_audioSystem.Play(component.SoundRoar, Filter.Pvs(uid, 4f, EntityManager), uid, component.SoundRoar.Params);
|
||||
Roar(component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -117,7 +313,6 @@ namespace Content.Server.Dragon
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
args.Handled = true;
|
||||
var target = args.Target;
|
||||
|
||||
@@ -164,22 +359,6 @@ namespace Content.Server.Dragon
|
||||
});
|
||||
}
|
||||
|
||||
private void OnDragonSpawnAction(EntityUid dragonuid, DragonComponent component, DragonSpawnActionEvent args)
|
||||
{
|
||||
if (component.SpawnPrototype == null)
|
||||
return;
|
||||
|
||||
// If dragon has spawns then add one.
|
||||
if (component.SpawnsLeft > 0)
|
||||
{
|
||||
Spawn(component.SpawnPrototype, Transform(dragonuid).Coordinates);
|
||||
component.SpawnsLeft--;
|
||||
return;
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("dragon-spawn-action-popup-message-fail-no-eggs"), dragonuid, Filter.Entities(dragonuid));
|
||||
}
|
||||
|
||||
private sealed class DragonDevourComplete : EntityEventArgs
|
||||
{
|
||||
public EntityUid User { get; }
|
||||
|
||||
@@ -15,8 +15,6 @@ namespace Content.Server.RatKing
|
||||
{
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly ActionsSystem _action = default!;
|
||||
[Dependency] private readonly DiseaseSystem _disease = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmos = default!;
|
||||
[Dependency] private readonly TransformSystem _xform = default!;
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace Content.Server.Sprite.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class RandomSpriteColorComponent : Component
|
||||
{
|
||||
// This should handle random states + colors for layers.
|
||||
// Saame with RandomSpriteState
|
||||
[DataField("selected")] public string? SelectedColor;
|
||||
[DataField("state")] public string BaseState = "error";
|
||||
|
||||
[DataField("colors")] public readonly Dictionary<string, Color> Colors = new();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Content.Server.Sprite.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class RandomSpriteStateComponent : Component
|
||||
{
|
||||
[DataField("spriteStates")] public List<string>? SpriteStates;
|
||||
|
||||
[DataField("spriteLayer")] public int SpriteLayer;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,53 @@
|
||||
using Content.Server.Sprite.Components;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Robust.Server.GameObjects;
|
||||
using System.Linq;
|
||||
using Content.Shared.Decals;
|
||||
using Content.Shared.Sprite;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Sprite;
|
||||
|
||||
public sealed class RandomSpriteSystem: EntitySystem
|
||||
public sealed class RandomSpriteSystem: SharedRandomSpriteSystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<RandomSpriteColorComponent, ComponentStartup>(OnSpriteColorStartup);
|
||||
SubscribeLocalEvent<RandomSpriteColorComponent, MapInitEvent>(OnSpriteColorMapInit);
|
||||
|
||||
SubscribeLocalEvent<RandomSpriteStateComponent, MapInitEvent>(OnSpriteStateMapInit);
|
||||
SubscribeLocalEvent<RandomSpriteComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<RandomSpriteComponent, MapInitEvent>(OnMapInit);
|
||||
}
|
||||
|
||||
private void OnSpriteColorStartup(EntityUid uid, RandomSpriteColorComponent component, ComponentStartup args)
|
||||
private void OnMapInit(EntityUid uid, RandomSpriteComponent component, MapInitEvent args)
|
||||
{
|
||||
UpdateColor(component);
|
||||
if (component.Selected.Count > 0)
|
||||
return;
|
||||
|
||||
if (component.Available.Count == 0)
|
||||
return;
|
||||
|
||||
var group = _random.Pick(component.Available);
|
||||
component.Selected.EnsureCapacity(group.Count);
|
||||
|
||||
foreach (var layer in group)
|
||||
{
|
||||
Color? color = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(layer.Value.Color))
|
||||
color = _random.Pick(_prototype.Index<ColorPalettePrototype>(layer.Value.Color).Colors.Values);
|
||||
|
||||
component.Selected.Add(layer.Key, (layer.Value.State, color));
|
||||
}
|
||||
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
private void OnSpriteColorMapInit(EntityUid uid, RandomSpriteColorComponent component, MapInitEvent args)
|
||||
private void OnGetState(EntityUid uid, RandomSpriteComponent component, ref ComponentGetState args)
|
||||
{
|
||||
component.SelectedColor = _random.Pick(component.Colors.Keys);
|
||||
UpdateColor(component);
|
||||
}
|
||||
|
||||
private void OnSpriteStateMapInit(EntityUid uid, RandomSpriteStateComponent component, MapInitEvent args)
|
||||
{
|
||||
if (component.SpriteStates == null) return;
|
||||
if (!TryComp<SpriteComponent>(uid, out var spriteComponent)) return;
|
||||
spriteComponent.LayerSetState(component.SpriteLayer, _random.Pick(component.SpriteStates));
|
||||
}
|
||||
|
||||
private void UpdateColor(RandomSpriteColorComponent component)
|
||||
{
|
||||
if (!TryComp<SpriteComponent>(component.Owner, out var spriteComponent) || component.SelectedColor == null) return;
|
||||
|
||||
spriteComponent.LayerSetState(0, component.BaseState);
|
||||
spriteComponent.LayerSetColor(0, component.Colors[component.SelectedColor]);
|
||||
args.State = new RandomSpriteColorComponentState()
|
||||
{
|
||||
Selected = component.Selected,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
9
Content.Shared/Dragon/DragonRiftComponentState.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Dragon;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class DragonRiftComponentState : ComponentState
|
||||
{
|
||||
public DragonRiftState State;
|
||||
}
|
||||
19
Content.Shared/Dragon/SharedDragonRiftComponent.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Dragon;
|
||||
|
||||
[NetworkedComponent]
|
||||
public abstract class SharedDragonRiftComponent : Component
|
||||
{
|
||||
[ViewVariables, DataField("state")]
|
||||
public DragonRiftState State = DragonRiftState.Charging;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum DragonRiftState : byte
|
||||
{
|
||||
Charging,
|
||||
AlmostFinished,
|
||||
Finished,
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Movement.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Is this entity always considered to be touching a wall?
|
||||
/// i.e. when weightless they're floaty but still have free movement.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class MovementAlwaysTouchingComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
@@ -8,6 +8,9 @@ using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Movement.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Ignores gravity entirely.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class MovementIgnoreGravityComponent : Component
|
||||
{
|
||||
@@ -17,7 +20,6 @@ namespace Content.Shared.Movement.Components
|
||||
[DataField("gravityState")] public bool Weightless = false;
|
||||
}
|
||||
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public sealed class MovementIgnoreGravityComponentState : ComponentState
|
||||
{
|
||||
|
||||
@@ -56,55 +56,55 @@ namespace Content.Shared.Movement.Components
|
||||
/// <summary>
|
||||
/// Minimum speed a mob has to be moving before applying movement friction.
|
||||
/// </summary>
|
||||
[DataField("minimumFrictionSpeed")]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("minimumFrictionSpeed")]
|
||||
public float MinimumFrictionSpeed = DefaultMinimumFrictionSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// The negative velocity applied for friction when weightless and providing inputs.
|
||||
/// </summary>
|
||||
[DataField("weightlessFriction")]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("weightlessFriction")]
|
||||
public float WeightlessFriction = DefaultWeightlessFriction;
|
||||
|
||||
/// <summary>
|
||||
/// The negative velocity applied for friction when weightless and not providing inputs.
|
||||
/// This is essentially how much their speed decreases per second.
|
||||
/// </summary>
|
||||
[DataField("weightlessFrictionNoInput")]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("weightlessFrictionNoInput")]
|
||||
public float WeightlessFrictionNoInput = DefaultWeightlessFrictionNoInput;
|
||||
|
||||
/// <summary>
|
||||
/// The movement speed modifier applied to a mob's total input velocity when weightless.
|
||||
/// </summary>
|
||||
[DataField("weightlessModifier")]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("weightlessModifier")]
|
||||
public float WeightlessModifier = DefaultWeightlessModifier;
|
||||
|
||||
/// <summary>
|
||||
/// The acceleration applied to mobs when moving and weightless.
|
||||
/// </summary>
|
||||
[DataField("weightlessAcceleration")]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("weightlessAcceleration")]
|
||||
public float WeightlessAcceleration = DefaultWeightlessAcceleration;
|
||||
|
||||
/// <summary>
|
||||
/// The acceleration applied to mobs when moving.
|
||||
/// </summary>
|
||||
[DataField("acceleration")]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("acceleration")]
|
||||
public float Acceleration = DefaultAcceleration;
|
||||
|
||||
/// <summary>
|
||||
/// The negative velocity applied for friction.
|
||||
/// </summary>
|
||||
[DataField("friction")]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("friction")]
|
||||
public float Friction = DefaultFriction;
|
||||
|
||||
/// <summary>
|
||||
/// The negative velocity applied for friction.
|
||||
/// </summary>
|
||||
[DataField("frictionNoInput")] public float? FrictionNoInput = null;
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("frictionNoInput")] public float? FrictionNoInput = null;
|
||||
|
||||
[DataField("baseWalkSpeed")]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("baseWalkSpeed")]
|
||||
public float BaseWalkSpeed { get; set; } = DefaultBaseWalkSpeed;
|
||||
|
||||
[DataField("baseSprintSpeed")]
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("baseSprintSpeed")]
|
||||
public float BaseSprintSpeed { get; set; } = DefaultBaseSprintSpeed;
|
||||
|
||||
[ViewVariables]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Movement.Systems;
|
||||
@@ -9,6 +10,12 @@ public sealed class MovementIgnoreGravitySystem : EntitySystem
|
||||
{
|
||||
SubscribeLocalEvent<MovementIgnoreGravityComponent, ComponentGetState>(GetState);
|
||||
SubscribeLocalEvent<MovementIgnoreGravityComponent, ComponentHandleState>(HandleState);
|
||||
SubscribeLocalEvent<MovementAlwaysTouchingComponent, CanWeightlessMoveEvent>(OnWeightless);
|
||||
}
|
||||
|
||||
private void OnWeightless(EntityUid uid, MovementAlwaysTouchingComponent component, ref CanWeightlessMoveEvent args)
|
||||
{
|
||||
args.CanMove = true;
|
||||
}
|
||||
|
||||
private void HandleState(EntityUid uid, MovementIgnoreGravityComponent component, ref ComponentHandleState args)
|
||||
|
||||
20
Content.Shared/Sprite/RandomSpriteComponent.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Sprite;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class RandomSpriteComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Available colors based on group, parsed layer enum, state, and color.
|
||||
/// Stored as a list so we can have groups of random sprites (e.g. tech_base + tech_flare for holoparasite)
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("available")]
|
||||
public List<Dictionary<string, (string State, string? Color)>> Available = new();
|
||||
|
||||
/// <summary>
|
||||
/// Selected colors
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("selected")]
|
||||
public Dictionary<string, (string State, Color? Color)> Selected = new();
|
||||
}
|
||||
11
Content.Shared/Sprite/SharedRandomSpriteSystem.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Sprite;
|
||||
|
||||
public abstract class SharedRandomSpriteSystem : EntitySystem {}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RandomSpriteColorComponentState : ComponentState
|
||||
{
|
||||
public Dictionary<string, (string State, Color? Color)> Selected = default!;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
atreides.ogg, c-20r.ogg, flaregun.ogg, mateba.ogg, minigun.ogg, mk58.ogg were taken from https://gitlab.com/cmdevs/colonial-warfare/-/tree/32cb5892413243cc74bb2d11df8e3085f8ef1164/sound/weapons
|
||||
They are licensed under CC-BY-SA 3.0
|
||||
|
||||
taser2.ogg and kinetic_accel.ogg were taken from https://github.com/tgstation/tgstation/tree/88d7dbfc105fbf40284d7b7c4587f8d23c0ac3ac
|
||||
rocket_launcher.ogg and taser2.ogg and kinetic_accel.ogg were taken from https://github.com/tgstation/tgstation/tree/88d7dbfc105fbf40284d7b7c4587f8d23c0ac3ac
|
||||
It is licensed under CC-BY-SA 3.0
|
||||
BIN
Resources/Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg
Normal file
@@ -2,7 +2,7 @@ devour-action-popup-message-structure = Your jaws dig into thick material..
|
||||
devour-action-popup-message-fail-target-not-valid = That doesn't look particularly edible.
|
||||
devour-action-popup-message-fail-target-alive = You can't consume creatures that are alive!
|
||||
|
||||
dragon-spawn-action-popup-message-fail-no-eggs = You don't have the stamina to create a carp!
|
||||
dragon-spawn-action-popup-message-fail-no-eggs = You don't have the stamina to do that!
|
||||
|
||||
|
||||
action-name-devour = [color=red]Devour[/color]
|
||||
@@ -10,3 +10,17 @@ action-description-devour = Attempt to break a structure with your jaws or swall
|
||||
|
||||
action-name-carp-summon = Summon carp
|
||||
action-description-carp-summon = Summon a carp to aid you at seizing the station!
|
||||
|
||||
# Rifts
|
||||
carp-rift-warning = A rift is causing an unnaturally large energy flux at {$location}. Stop it at all costs!
|
||||
carp-rift-duplicate = Cannot have 2 charging rifts at the same time!
|
||||
carp-rift-examine = It is [color=yellow]{$percentage}%[/color] charged!
|
||||
carp-rift-max = You have reached your maximum amount of rifts
|
||||
carp-rift-anchor = Rifts require a stable surface to spawn.
|
||||
carp-rift-weakened = You are unable to summon more rifts in your weakened state.
|
||||
carp-rift-destroyed = A rift has been destroyed! You are now weakened temporarily.
|
||||
|
||||
# Round end
|
||||
dragon-round-end-summary = The dragons were:
|
||||
dragon-round-end-dragon = {$name} with {$count} rifts
|
||||
dragon-round-end-dragon-player = {$name} ({$player}) with {$count} rifts
|
||||
|
||||
@@ -307,6 +307,7 @@
|
||||
baseSprintSpeed : 6
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
netsync: false
|
||||
layers:
|
||||
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||
state: butterfly
|
||||
@@ -327,16 +328,10 @@
|
||||
0: Alive
|
||||
5: Critical
|
||||
10: Dead
|
||||
- type: RandomSpriteColor
|
||||
state: butterfly
|
||||
colors:
|
||||
blue: "#1861d5"
|
||||
red: "#951710"
|
||||
pink: "#d5188d"
|
||||
brown: "#a05212"
|
||||
green: "#0e7f1b"
|
||||
cyan: "#18a2d5"
|
||||
yellow: "#d58c18"
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
butterfly: Rainbow
|
||||
- type: Appearance
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
- MobMask
|
||||
layer:
|
||||
- MobLayer
|
||||
- type: MovementIgnoreGravity
|
||||
- type: MovementAlwaysTouching
|
||||
- type: MobState
|
||||
thresholds:
|
||||
0: Alive
|
||||
|
||||
@@ -1,77 +1,95 @@
|
||||
- type: entity
|
||||
name: space carp
|
||||
id: MobCarp
|
||||
id: BaseMobCarp
|
||||
parent: SimpleSpaceMobBase
|
||||
description: It's a space carp.
|
||||
abstract: true
|
||||
components:
|
||||
- type: InputMover
|
||||
- type: MobMover
|
||||
- type: UtilityNPC
|
||||
behaviorSets:
|
||||
- Idle
|
||||
- UnarmedAttackHostiles
|
||||
- type: AiFactionTag
|
||||
factions:
|
||||
- SimpleHostile
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
layers:
|
||||
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||
state: alive
|
||||
sprite: Mobs/Aliens/Carps/space.rsi
|
||||
- type: CombatMode
|
||||
disarmAction:
|
||||
enabled: false
|
||||
autoPopulate: false
|
||||
name: action-name-disarm
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.40
|
||||
mass: 40
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
- MobLayer
|
||||
- type: MobState
|
||||
thresholds:
|
||||
0: Alive
|
||||
50: Critical
|
||||
100: Dead
|
||||
- type: MovementIgnoreGravity
|
||||
- type: Appearance
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
Alive:
|
||||
Base: alive
|
||||
Critical:
|
||||
Base: crit
|
||||
Dead:
|
||||
Base: dead
|
||||
- type: Butcherable
|
||||
spawned:
|
||||
- id: FoodMeatFish
|
||||
amount: 2
|
||||
- type: MeleeWeapon
|
||||
range: 1.5
|
||||
arcwidth: 0
|
||||
arc: bite
|
||||
hitSound:
|
||||
path: /Audio/Effects/bite.ogg
|
||||
damage:
|
||||
types:
|
||||
Piercing: 5
|
||||
Slash: 10
|
||||
- type: ReplacementAccent
|
||||
accent: genericAggressive
|
||||
- type: TypingIndicator
|
||||
proto: alien
|
||||
- type: NoSlip
|
||||
- type: Tag
|
||||
tags:
|
||||
- Carp
|
||||
- type: InputMover
|
||||
- type: MobMover
|
||||
- type: UtilityNPC
|
||||
behaviorSets:
|
||||
- Idle
|
||||
- UnarmedAttackHostiles
|
||||
- type: AiFactionTag
|
||||
factions:
|
||||
- SimpleHostile
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
netsync: false
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: base
|
||||
sprite: Mobs/Aliens/Carps/space.rsi
|
||||
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
state: mouth
|
||||
sprite: Mobs/Aliens/Carps/space.rsi
|
||||
shader: unshaded
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
base: Rainbow
|
||||
enum.DamageStateVisualLayers.BaseUnshaded:
|
||||
mouth: ""
|
||||
- type: CombatMode
|
||||
disarmAction:
|
||||
enabled: false
|
||||
autoPopulate: false
|
||||
name: action-name-disarm
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.40
|
||||
mass: 40
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
- MobLayer
|
||||
- type: MobState
|
||||
thresholds:
|
||||
0: Alive
|
||||
50: Critical
|
||||
100: Dead
|
||||
- type: MovementAlwaysTouching
|
||||
- type: Appearance
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
Alive:
|
||||
Base: base
|
||||
BaseUnshaded: mouth
|
||||
Dead:
|
||||
Base: base_dead
|
||||
BaseUnshaded: dead_mouth
|
||||
- type: Butcherable
|
||||
spawned:
|
||||
- id: FoodMeatFish
|
||||
amount: 2
|
||||
- type: MeleeWeapon
|
||||
range: 1.5
|
||||
arcwidth: 0
|
||||
arc: bite
|
||||
hitSound:
|
||||
path: /Audio/Effects/bite.ogg
|
||||
damage:
|
||||
types:
|
||||
Piercing: 5
|
||||
Slash: 10
|
||||
- type: TypingIndicator
|
||||
proto: alien
|
||||
- type: NoSlip
|
||||
- type: Tag
|
||||
tags:
|
||||
- Carp
|
||||
- DoorBumpOpener
|
||||
|
||||
- type: entity
|
||||
parent: BaseMobCarp
|
||||
id: MobCarp
|
||||
components:
|
||||
- type: ReplacementAccent
|
||||
accent: genericAggressive
|
||||
|
||||
- type: entity
|
||||
name: magicarp
|
||||
@@ -79,14 +97,14 @@
|
||||
id: MobCarpMagic
|
||||
description: Looks like some kind of fish. Might be magical.
|
||||
components:
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
layers:
|
||||
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||
state: alive
|
||||
sprite: Mobs/Aliens/Carps/magic.rsi
|
||||
- type: TypingIndicator
|
||||
proto: guardian
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: base
|
||||
sprite: Mobs/Aliens/Carps/magic.rsi
|
||||
- type: TypingIndicator
|
||||
proto: guardian
|
||||
|
||||
- type: entity
|
||||
name: holocarp
|
||||
@@ -94,37 +112,37 @@
|
||||
id: MobCarpHolo
|
||||
description: Carp made out of holographic energies. Sadly for you, it is very much real.
|
||||
components:
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
layers:
|
||||
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||
state: alive
|
||||
sprite: Mobs/Aliens/Carps/holo.rsi
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.40
|
||||
mass: 5
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
- Opaque
|
||||
- type: TypingIndicator
|
||||
proto: robot
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: base
|
||||
sprite: Mobs/Aliens/Carps/holo.rsi
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.40
|
||||
mass: 5
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
- Opaque
|
||||
- type: TypingIndicator
|
||||
proto: robot
|
||||
|
||||
- type: entity
|
||||
id: MobCarpSalvage
|
||||
parent: MobCarp
|
||||
suffix: "Salvage Ruleset"
|
||||
components:
|
||||
- type: GhostTakeoverAvailable
|
||||
prob: 0.33
|
||||
name: space carp on salvage wreck
|
||||
description: |
|
||||
Defend the loot inside the salvage wreck!
|
||||
- type: SalvageMobRestrictions
|
||||
- type: GhostTakeoverAvailable
|
||||
prob: 0.33
|
||||
name: space carp on salvage wreck
|
||||
description: |
|
||||
Defend the loot inside the salvage wreck!
|
||||
- type: SalvageMobRestrictions
|
||||
|
||||
- type: entity
|
||||
name: space carp
|
||||
@@ -132,8 +150,7 @@
|
||||
suffix: DragonBrood
|
||||
parent: MobCarp
|
||||
components:
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Sentient Carp
|
||||
description: Help the dragon flood the station with carps!
|
||||
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Sentient Carp
|
||||
description: Help the dragon flood the station with carps!
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
thresholds:
|
||||
0: Alive
|
||||
15: Dead
|
||||
- type: MovementIgnoreGravity
|
||||
- type: MovementAlwaysTouching
|
||||
- type: Appearance
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
|
||||
@@ -5,106 +5,112 @@
|
||||
suffix:
|
||||
description: A flying leviathan, loosely related to space carps.
|
||||
components:
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Space dragon!
|
||||
description: Crash, roast, flood the station with carps!
|
||||
- type: Speech
|
||||
- type: CombatMode
|
||||
disarmAction:
|
||||
enabled: false
|
||||
autoPopulate: false
|
||||
name: action-name-disarm
|
||||
- type: MobMover
|
||||
- type: InputMover
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed : 5
|
||||
baseSprintSpeed : 5
|
||||
- type: Sprite
|
||||
sprite: Mobs/Aliens/Carps/dragon.rsi
|
||||
noRot: true
|
||||
# TODO: Randomise colors when RandomSpriteColor isn't poopoo
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: alive
|
||||
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
state: alive-unshaded
|
||||
shader: unshaded
|
||||
- type: Appearance
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
Alive:
|
||||
Base: alive
|
||||
BaseUnshaded: alive-unshaded
|
||||
Critical:
|
||||
Base: crit
|
||||
Dead:
|
||||
Base: dead
|
||||
BaseUnshaded: dead-unshaded
|
||||
- type: Physics
|
||||
bodyType: KinematicController
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.40
|
||||
mass: 50
|
||||
mask:
|
||||
- FlyingMobMask
|
||||
layer:
|
||||
- FlyingMobLayer
|
||||
- type: MobState
|
||||
thresholds:
|
||||
0: Alive
|
||||
450: Critical
|
||||
500: Dead
|
||||
- type: Metabolizer
|
||||
solutionOnBody: false
|
||||
updateFrequency: 0.25
|
||||
metabolizerTypes: [Dragon]
|
||||
groups:
|
||||
- id: Medicine
|
||||
- id: Poison
|
||||
- type: MovementIgnoreGravity
|
||||
- type: NoSlip
|
||||
- type: Butcherable
|
||||
spawned:
|
||||
- id: FoodMeatDragon
|
||||
amount: 2
|
||||
- type: InteractionPopup
|
||||
successChance: 0.25 # It's no goose, but you better smell like carp.
|
||||
interactSuccessString: petting-success-dragon
|
||||
interactFailureString: petting-failure-dragon
|
||||
interactFailureSound:
|
||||
path: /Audio/Animals/space_dragon_roar.ogg
|
||||
soundPerceivedByOthers: false # A 75% chance for a loud roar would get old fast.
|
||||
- type: MeleeWeapon
|
||||
hitSound:
|
||||
path: /Audio/Effects/bite.ogg
|
||||
damage:
|
||||
types:
|
||||
Piercing: 15
|
||||
Slash: 15
|
||||
- type: Dragon
|
||||
spawnsLeft: 2
|
||||
spawnsProto: MobCarpDragon
|
||||
devourAction:
|
||||
event: !type:DragonDevourActionEvent
|
||||
icon: Interface/Actions/devour.png
|
||||
name: action-name-devour
|
||||
description: action-description-devour
|
||||
devourChemical: Ichor
|
||||
devourHealRate: 15.0
|
||||
whitelist:
|
||||
components:
|
||||
- MobState
|
||||
- Door
|
||||
tags:
|
||||
- Wall
|
||||
spawnAction:
|
||||
event: !type:DragonSpawnActionEvent
|
||||
icon: Interface/Actions/carp_summon.png
|
||||
name: action-name-carp-summon
|
||||
description: action-description-carp-summon
|
||||
useDelay: 5
|
||||
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Space dragon
|
||||
description: Call in 3 carp rifts and take over this quadrant! You have only 5 minutes in between each rift before you will disappear.
|
||||
- type: Speech
|
||||
- type: CombatMode
|
||||
disarmAction:
|
||||
enabled: false
|
||||
autoPopulate: false
|
||||
name: action-name-disarm
|
||||
- type: MobMover
|
||||
- type: InputMover
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 3
|
||||
baseSprintSpeed: 5
|
||||
weightlessModifier: 1.5
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
alive: Rainbow
|
||||
- type: Sprite
|
||||
sprite: Mobs/Aliens/Carps/dragon.rsi
|
||||
netsync: false
|
||||
noRot: true
|
||||
layers:
|
||||
- map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
state: alive
|
||||
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
state: alive-unshaded
|
||||
shader: unshaded
|
||||
- type: Appearance
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
Alive:
|
||||
Base: alive
|
||||
BaseUnshaded: alive-unshaded
|
||||
Critical:
|
||||
Base: crit
|
||||
Dead:
|
||||
Base: dead
|
||||
BaseUnshaded: dead-unshaded
|
||||
- type: Physics
|
||||
bodyType: KinematicController
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.40
|
||||
mass: 50
|
||||
mask:
|
||||
- FlyingMobMask
|
||||
layer:
|
||||
- FlyingMobLayer
|
||||
- type: MobState
|
||||
thresholds:
|
||||
0: Alive
|
||||
450: Critical
|
||||
500: Dead
|
||||
- type: Metabolizer
|
||||
solutionOnBody: false
|
||||
updateFrequency: 0.25
|
||||
metabolizerTypes: [ Dragon ]
|
||||
groups:
|
||||
- id: Medicine
|
||||
- id: Poison
|
||||
- type: MovementAlwaysTouching
|
||||
- type: NoSlip
|
||||
- type: Butcherable
|
||||
spawned:
|
||||
- id: FoodMeatDragon
|
||||
amount: 2
|
||||
- type: InteractionPopup
|
||||
successChance: 0.25 # It's no goose, but you better smell like carp.
|
||||
interactSuccessString: petting-success-dragon
|
||||
interactFailureString: petting-failure-dragon
|
||||
interactFailureSound:
|
||||
path: /Audio/Animals/space_dragon_roar.ogg
|
||||
soundPerceivedByOthers: false # A 75% chance for a loud roar would get old fast.
|
||||
- type: MeleeWeapon
|
||||
hitSound:
|
||||
path: /Audio/Effects/bite.ogg
|
||||
damage:
|
||||
types:
|
||||
Piercing: 15
|
||||
Slash: 15
|
||||
- type: Dragon
|
||||
spawnsLeft: 2
|
||||
spawnsProto: MobCarpDragon
|
||||
devourAction:
|
||||
event: !type:DragonDevourActionEvent
|
||||
icon: Interface/Actions/devour.png
|
||||
name: action-name-devour
|
||||
description: action-description-devour
|
||||
devourChemical: Ichor
|
||||
devourHealRate: 15.0
|
||||
whitelist:
|
||||
components:
|
||||
- MobState
|
||||
- Door
|
||||
tags:
|
||||
- Wall
|
||||
spawnRiftAction:
|
||||
event: !type:DragonSpawnRiftActionEvent
|
||||
icon:
|
||||
sprite: Interface/Actions/carp_rift.rsi
|
||||
state: icon
|
||||
name: action-name-carp-rift
|
||||
description: action-description-carp-rift
|
||||
useDelay: 1
|
||||
|
||||
@@ -5,78 +5,94 @@
|
||||
id: MobGuardianBase
|
||||
description: guardian
|
||||
components:
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Guardian
|
||||
description: Listen to your owner. Don't tank damage. Punch people hard.
|
||||
- type: Input
|
||||
context: "human"
|
||||
- type: MobMover
|
||||
- type: InputMover
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed : 7
|
||||
baseSprintSpeed : 7
|
||||
- type: DamageOnHighSpeedImpact
|
||||
damage:
|
||||
types:
|
||||
Blunt: 5
|
||||
soundHit:
|
||||
path: /Audio/Effects/hit_kick.ogg
|
||||
# TODO: Randomise sprites and randomise the layer color
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
sprite: Mobs/Aliens/Guardians/guardians.rsi
|
||||
layers:
|
||||
- state: tech_base
|
||||
- state: tech_flare
|
||||
color: "#40a7d7"
|
||||
shader: unshaded
|
||||
noRot: true
|
||||
- type: Clickable
|
||||
- type: InteractionOutline
|
||||
- type: Physics
|
||||
bodyType: KinematicController
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mask:
|
||||
- FlyingMobMask
|
||||
layer:
|
||||
- FlyingMobLayer
|
||||
- type: Damageable
|
||||
damageContainer: Biological
|
||||
- type: MobState
|
||||
thresholds:
|
||||
0: Alive
|
||||
- type: HeatResistance
|
||||
- type: CombatMode
|
||||
- type: Internals
|
||||
- type: Examiner
|
||||
- type: Speech
|
||||
- type: TypingIndicator
|
||||
proto: guardian
|
||||
- type: Pullable
|
||||
- type: MeleeWeapon
|
||||
range: 2
|
||||
arcwidth: 30
|
||||
arc: fist
|
||||
cooldownTime: 0.7
|
||||
arcCooldownTime: 0.7
|
||||
damage:
|
||||
types:
|
||||
Blunt: 22
|
||||
- type: Actions
|
||||
- type: Guardian
|
||||
- type: InteractionPopup
|
||||
interactSuccessString: petting-success-holo
|
||||
interactFailureString: petting-failure-holo
|
||||
successChance: 0.7
|
||||
- type: Tag
|
||||
tags:
|
||||
- CannotSuicide
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Guardian
|
||||
description: Listen to your owner. Don't tank damage. Punch people hard.
|
||||
- type: Input
|
||||
context: "human"
|
||||
- type: MobMover
|
||||
- type: InputMover
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 4
|
||||
baseSprintSpeed: 5.5
|
||||
- type: DamageOnHighSpeedImpact
|
||||
damage:
|
||||
types:
|
||||
Blunt: 5
|
||||
soundHit:
|
||||
path: /Audio/Effects/hit_kick.ogg
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
magic_base: ""
|
||||
enum.DamageStateVisualLayers.BaseUnshaded:
|
||||
magic_flare: Sixteen
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
miner_base: ""
|
||||
enum.DamageStateVisualLayers.BaseUnshaded:
|
||||
miner_flare: Sixteen
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
tech_base: ""
|
||||
enum.DamageStateVisualLayers.BaseUnshaded:
|
||||
tech_flare: Sixteen
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
sprite: Mobs/Aliens/Guardians/guardians.rsi
|
||||
netsync: false
|
||||
layers:
|
||||
- state: tech_base
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- state: tech_flare
|
||||
map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
color: "#40a7d7"
|
||||
shader: unshaded
|
||||
noRot: true
|
||||
- type: Clickable
|
||||
- type: InteractionOutline
|
||||
- type: Physics
|
||||
bodyType: KinematicController
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
- shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
mass: 10
|
||||
mask:
|
||||
- FlyingMobMask
|
||||
layer:
|
||||
- FlyingMobLayer
|
||||
- type: Damageable
|
||||
damageContainer: Biological
|
||||
- type: MobState
|
||||
thresholds:
|
||||
0: Alive
|
||||
- type: HeatResistance
|
||||
- type: CombatMode
|
||||
- type: Internals
|
||||
- type: Examiner
|
||||
- type: Speech
|
||||
- type: TypingIndicator
|
||||
proto: guardian
|
||||
- type: Pullable
|
||||
- type: MeleeWeapon
|
||||
range: 2
|
||||
arcwidth: 30
|
||||
arc: fist
|
||||
cooldownTime: 0.7
|
||||
arcCooldownTime: 0.7
|
||||
damage:
|
||||
types:
|
||||
Blunt: 22
|
||||
- type: Actions
|
||||
- type: Guardian
|
||||
- type: InteractionPopup
|
||||
interactSuccessString: petting-success-holo
|
||||
interactFailureString: petting-failure-holo
|
||||
successChance: 0.7
|
||||
- type: Tag
|
||||
tags:
|
||||
- CannotSuicide
|
||||
|
||||
# From the uplink injector
|
||||
- type: entity
|
||||
@@ -85,20 +101,22 @@
|
||||
parent: MobGuardianBase
|
||||
description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself.
|
||||
components:
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Holoparasite
|
||||
description: Listen to your owner. Don't tank damage. Punch people hard.
|
||||
- type: NameIdentifier
|
||||
group: Holoparasite
|
||||
- type: TypingIndicator
|
||||
proto: holo
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: tech_base
|
||||
- state: tech_flare
|
||||
color: "#40a7d7"
|
||||
shader: unshaded
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Holoparasite
|
||||
description: Listen to your owner. Don't tank damage. Punch people hard.
|
||||
- type: NameIdentifier
|
||||
group: Holoparasite
|
||||
- type: TypingIndicator
|
||||
proto: holo
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: tech_base
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- state: tech_flare
|
||||
map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
color: "#40a7d7"
|
||||
shader: unshaded
|
||||
|
||||
# From Wizard deck of cards
|
||||
- type: entity
|
||||
@@ -107,13 +125,19 @@
|
||||
id: MobIfritGuardian
|
||||
description: A corrupted jinn, ripped from fitra to serve the wizard's petty needs. It stands wicked, tuning into it's owner's life to sustain itself.
|
||||
components:
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Ifrit
|
||||
description: Listen to your owner. Don't tank damage. Punch people hard.
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: magic_base
|
||||
- state: magic_flare
|
||||
color: "#d14730"
|
||||
shader: unshaded
|
||||
- type: GhostTakeoverAvailable
|
||||
makeSentient: true
|
||||
name: Ifrit
|
||||
description: Listen to your owner. Don't tank damage. Punch people hard.
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.BaseUnshaded:
|
||||
magic_flare: Sixteen
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: magic_base
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- state: magic_flare
|
||||
map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||
color: "#40a7d7"
|
||||
shader: unshaded
|
||||
|
||||
@@ -176,14 +176,20 @@
|
||||
- Nugget
|
||||
- type: Sprite
|
||||
sprite: Objects/Consumable/Food/Baked/nuggets.rsi
|
||||
state: tendie
|
||||
netsync: true
|
||||
- type: RandomSpriteState
|
||||
spriteStates:
|
||||
- tendie
|
||||
- lizard
|
||||
- star
|
||||
- corgi
|
||||
layers:
|
||||
- state: tendie
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
netsync: false
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
tendie: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
lizard: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
star: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
corgi: ""
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
food:
|
||||
|
||||
@@ -126,8 +126,13 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Consumable/Food/egg.rsi
|
||||
state: icon
|
||||
- type: RandomSpriteState
|
||||
spriteStates:
|
||||
- icon
|
||||
- white
|
||||
layers:
|
||||
- state: icon
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
netsync: false
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
icon: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
white: ""
|
||||
|
||||
@@ -237,11 +237,16 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Consumable/Food/frozen.rsi
|
||||
state: stick
|
||||
- type: RandomSpriteState
|
||||
spriteStates:
|
||||
- stick
|
||||
- stick2
|
||||
netsync: false
|
||||
layers:
|
||||
- state: stick
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
stick: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
stick2: ""
|
||||
- type: Tag
|
||||
tags:
|
||||
- Trash
|
||||
|
||||
@@ -87,12 +87,14 @@
|
||||
tags:
|
||||
- Raw
|
||||
- type: Sprite
|
||||
netsync: true
|
||||
netsync: false
|
||||
state: bacon
|
||||
- type: RandomSpriteState
|
||||
spriteStates:
|
||||
- bacon
|
||||
- bacon2
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
bacon: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
bacon2: ""
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
food:
|
||||
@@ -501,11 +503,13 @@
|
||||
layers:
|
||||
- state: plate-meat
|
||||
- state: bacon-cooked
|
||||
- type: RandomSpriteState
|
||||
spriteLayer: 1
|
||||
spriteStates:
|
||||
- bacon-cooked
|
||||
- bacon2-cooked
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
bacon-cooked: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
bacon2-cooked: ""
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
food:
|
||||
@@ -608,12 +612,16 @@
|
||||
- type: Food
|
||||
trash: FoodPlateSmall
|
||||
- type: Sprite
|
||||
netsync: true
|
||||
state: chicken-fried
|
||||
- type: RandomSpriteState
|
||||
spriteStates:
|
||||
- chicken-fried
|
||||
- chicken2-fried
|
||||
netsync: false
|
||||
layers:
|
||||
- state: chicken-fried
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
chicken-fried: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
chicken2-fried: ""
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
food:
|
||||
|
||||
@@ -5,13 +5,19 @@
|
||||
description: It's a shard of some unknown material.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Materials/Shards/shard.rsi
|
||||
state: shard1
|
||||
- type: RandomSpriteState
|
||||
spriteStates:
|
||||
- shard1
|
||||
- shard2
|
||||
- shard3
|
||||
layers:
|
||||
- sprite: Objects/Materials/Shards/shard.rsi
|
||||
state: shard1
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
netsync: false
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
shard1: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
shard2: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
shard3: ""
|
||||
- type: ItemCooldown
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Misc/books.rsi
|
||||
netsync: false
|
||||
layers:
|
||||
- state: book0
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- type: Paper
|
||||
- type: ActivatableUI
|
||||
key: enum.PaperUiKey.Key
|
||||
@@ -21,15 +23,23 @@
|
||||
id: BookRandom
|
||||
suffix: random
|
||||
components:
|
||||
- type: RandomSpriteState
|
||||
spriteLayer: 0
|
||||
spriteStates:
|
||||
- book0
|
||||
- book1
|
||||
- book2
|
||||
- book3
|
||||
- book4
|
||||
- book5
|
||||
- book6
|
||||
- book7
|
||||
- book8
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book0: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book1: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book2: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book3: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book4: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book5: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book6: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book7: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book8: ""
|
||||
|
||||
@@ -4,21 +4,34 @@
|
||||
id: Lighter
|
||||
description: "A simple plastic cigarette lighter."
|
||||
components:
|
||||
- type: RandomSpriteState #this has to be before sprite component for the flame to toggle right because weldercomponent behaves weird (and i dont trust myself to fix it right)
|
||||
spriteStates:
|
||||
- basic_icon_base-1
|
||||
- basic_icon_base-2
|
||||
- basic_icon_base-3
|
||||
- basic_icon_base-4
|
||||
- basic_icon_base-5
|
||||
- basic_icon_base-6
|
||||
- basic_icon_base-7
|
||||
- basic_icon_base-8
|
||||
- basic_icon_base-9
|
||||
- basic_icon_base-10
|
||||
- basic_icon_base-11
|
||||
# Sloth: What is this comment ?????????
|
||||
- type: RandomSprite #this has to be before sprite component for the flame to toggle right because weldercomponent behaves weird (and i dont trust myself to fix it right)
|
||||
available:
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-1: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-2: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-3: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-4: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-5: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-6: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-7: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-8: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-9: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-10: ""
|
||||
- enum.WelderLayers.Base:
|
||||
basic_icon_base-11: ""
|
||||
- type: Sprite
|
||||
sprite: Objects/Tools/lighters.rsi
|
||||
netsync: false
|
||||
layers:
|
||||
- state: icon_map
|
||||
map: ["enum.WelderLayers.Base"]
|
||||
@@ -69,16 +82,10 @@
|
||||
id: CheapLighter
|
||||
description: "A dangerously inexpensive plastic lighter, don't burn your thumb!"
|
||||
components:
|
||||
- type: RandomSpriteColor
|
||||
state: cheap_icon_base
|
||||
colors:
|
||||
blue: "#1861d5"
|
||||
red: "#951710"
|
||||
pink: "#d5188d"
|
||||
brown: "#a05212"
|
||||
green: "#0e7f1b"
|
||||
cyan: "#18a2d5"
|
||||
yellow: "#d58c18" #all colours proudly stolen from wirecutters
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.WelderLayers.Base:
|
||||
cheap_icon_base: Rainbow
|
||||
- type: Sprite
|
||||
sprite: Objects/Tools/lighters.rsi
|
||||
layers:
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
- Wirecutter
|
||||
- type: Sprite
|
||||
sprite: Objects/Tools/wirecutters.rsi
|
||||
netsync: false
|
||||
layers:
|
||||
- state: cutters-map
|
||||
- state: cutters
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- state: cutters-cutty-thingy
|
||||
- type: ItemCooldown
|
||||
- type: MeleeWeapon
|
||||
@@ -26,16 +28,10 @@
|
||||
- Cutting
|
||||
useSound:
|
||||
path: /Audio/Items/wirecutter.ogg
|
||||
- type: RandomSpriteColor
|
||||
state: cutters
|
||||
colors:
|
||||
blue: "#1861d5"
|
||||
red: "#951710"
|
||||
pink: "#d5188d"
|
||||
brown: "#a05212"
|
||||
green: "#0e7f1b"
|
||||
cyan: "#18a2d5"
|
||||
yellow: "#d58c18"
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
cutters: Rainbow
|
||||
- type: Item
|
||||
sprite: Objects/Tools/wirecutters.rsi
|
||||
|
||||
@@ -53,8 +49,10 @@
|
||||
- Screwdriver
|
||||
- type: Sprite
|
||||
sprite: Objects/Tools/screwdriver.rsi
|
||||
netsync: false
|
||||
layers:
|
||||
- state: screwdriver-map
|
||||
- state: screwdriver
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- state: screwdriver-screwybits
|
||||
- type: Item
|
||||
sprite: Objects/Tools/screwdriver.rsi
|
||||
@@ -68,16 +66,10 @@
|
||||
- Screwing
|
||||
useSound:
|
||||
collection: Screwdriver
|
||||
- type: RandomSpriteColor
|
||||
state: screwdriver
|
||||
colors:
|
||||
blue: "#1861d5"
|
||||
red: "#ff0000"
|
||||
pink: "#d5188d"
|
||||
brown: "#a05212"
|
||||
green: "#0e7f1b"
|
||||
cyan: "#18a2d5"
|
||||
yellow: "#ffa500"
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
screwdriver: Rainbow
|
||||
|
||||
- type: entity
|
||||
name: wrench
|
||||
|
||||
@@ -9,15 +9,21 @@
|
||||
layers:
|
||||
- state: base
|
||||
- state: book-0
|
||||
- type: RandomSpriteState
|
||||
spriteLayer: 1
|
||||
spriteStates:
|
||||
- book-0
|
||||
- book-1
|
||||
- book-2
|
||||
- book-3
|
||||
- book-4
|
||||
- book-5
|
||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book-0: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book-1: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book-2: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book-3: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book-4: ""
|
||||
- enum.DamageStateVisualLayers.Base:
|
||||
book-5: ""
|
||||
- type: Damageable
|
||||
damageModifierSet: Wood
|
||||
damageContainer: Inorganic
|
||||
|
||||
39
Resources/Prototypes/Entities/Structures/Specific/dragon.yml
Normal file
@@ -0,0 +1,39 @@
|
||||
- type: entity
|
||||
id: CarpRift
|
||||
name: carp rift
|
||||
description: A rift akin to the ones space carp use to travel long distances.
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
components:
|
||||
- type: DragonRift
|
||||
- type: Transform
|
||||
anchored: true
|
||||
- type: Physics
|
||||
bodyType: Static
|
||||
- type: Fixtures
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
layers:
|
||||
- sprite: Structures/Specific/carp_rift.rsi
|
||||
state: icon
|
||||
color: "#569fff"
|
||||
shader: unshaded
|
||||
- type: InteractionOutline
|
||||
- type: Clickable
|
||||
- type: PointLight
|
||||
enabled: true
|
||||
color: "#366db5"
|
||||
radius: 10.0
|
||||
energy: 5.0
|
||||
netsync: false
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Metallic
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 300
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
@@ -32,6 +32,17 @@
|
||||
earliestStart: 15
|
||||
maxOccurrences: 3
|
||||
|
||||
- type: gameRule
|
||||
id: Dragon
|
||||
config:
|
||||
!type:StationEventRuleConfiguration
|
||||
id: Dragon
|
||||
weight: 10
|
||||
endAfter: 2
|
||||
earliestStart: 15
|
||||
maxOccurrences: 7
|
||||
minimumPlayers: 15
|
||||
|
||||
- type: gameRule
|
||||
id: FalseAlarm
|
||||
config:
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
- type: palette
|
||||
id: Rainbow
|
||||
name: Rainbow
|
||||
colors:
|
||||
blue: "#1861d5"
|
||||
red: "#951710"
|
||||
pink: "#d5188d"
|
||||
brown: "#a05212"
|
||||
green: "#0e7f1b"
|
||||
cyan: "#18a2d5"
|
||||
yellow: "#d58c18"
|
||||
|
||||
- type: palette
|
||||
id: Sixteen
|
||||
name: Sixteen
|
||||
colors:
|
||||
|
||||
BIN
Resources/Textures/Interface/Actions/carp_rift.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
21
Resources/Textures/Interface/Actions/carp_rift.rsi/meta.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "https://github.com/tgstation/tgstation/blob/19da0cee1869bad0186d54d6bcd8a55ed30b9db6/icons/obj/carp_rift.dmi",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "icon",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -33,29 +33,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "crit",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "alive",
|
||||
"name": "base",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
|
||||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 473 B |
@@ -14,10 +14,7 @@
|
||||
"name": "dead"
|
||||
},
|
||||
{
|
||||
"name": "crit"
|
||||
},
|
||||
{
|
||||
"name": "alive",
|
||||
"name": "base",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
|
||||
|
Before Width: | Height: | Size: 3.6 KiB |
BIN
Resources/Textures/Mobs/Aliens/Carps/space.rsi/base.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Resources/Textures/Mobs/Aliens/Carps/space.rsi/base_dead.png
Normal file
|
After Width: | Height: | Size: 517 B |
|
Before Width: | Height: | Size: 293 B |
|
Before Width: | Height: | Size: 294 B |
BIN
Resources/Textures/Mobs/Aliens/Carps/space.rsi/dead_mouth.png
Normal file
|
After Width: | Height: | Size: 135 B |
@@ -11,13 +11,39 @@
|
||||
"name": "icon"
|
||||
},
|
||||
{
|
||||
"name": "dead"
|
||||
"name": "mouth",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
],
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
],
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
],
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "crit"
|
||||
"name": "dead_mouth"
|
||||
},
|
||||
{
|
||||
"name": "alive",
|
||||
"name": "base_dead"
|
||||
},
|
||||
{
|
||||
"name": "base",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
|
||||
BIN
Resources/Textures/Mobs/Aliens/Carps/space.rsi/mouth.png
Normal file
|
After Width: | Height: | Size: 590 B |
@@ -1 +0,0 @@
|
||||
Eventually we'll have some kind of unifying "RandomSpriteStateComponent" but til now i'm just leaving these here in protest.
|
||||
@@ -1 +0,0 @@
|
||||
Eventually we'll have some kind of unifying "RandomSpriteStateComponent" but til now i'm just leaving these here in protest.
|
||||
BIN
Resources/Textures/Structures/Specific/carp_rift.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "https://github.com/tgstation/tgstation/blob/19da0cee1869bad0186d54d6bcd8a55ed30b9db6/icons/obj/carp_rift.dmi",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "icon",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||