Compare commits

..

28 Commits

Author SHA1 Message Date
Deserty0
3fb169a18a Explode system numerics 2025-10-29 23:19:03 +10:00
Deserty0
8564d878c3 Update CP14FishingSystem.cs 2025-10-29 23:15:46 +10:00
Deserty0
29cbf0560f Cleanup 2025-10-29 23:06:20 +10:00
Ed
2da1977ae1 clean up 2025-10-28 13:46:04 +03:00
Deserty0
f53c68d272 123 2025-10-27 00:22:59 +10:00
Deserty0
44b757a033 Merge remote-tracking branch 'upstream/master' into des-fishing 2025-10-26 22:45:15 +10:00
Deserty0
a1e452de63 comments 2025-10-17 14:46:01 +10:00
Deserty0
f31e82f7b3 123 2025-10-17 14:28:03 +10:00
Deserty0
2fdd3923f5 swaggy swaggy swags 2025-10-05 17:33:13 +10:00
Deserty0
88575e2286 I am become Death, the Code Destroyer 2025-10-05 16:48:09 +10:00
Deserty0
636b2a5514 prediction
needs heavy cleanups
2025-10-04 17:00:47 +10:00
Deserty0
90797f88b6 help me 2025-09-19 22:22:56 +10:00
Deserty0
122193bc7b quick fix 2025-09-12 13:45:21 +10:00
Deserty0
0c7dd03f79 я усталь 2025-09-12 13:44:21 +10:00
Deserty0
59d776ca72 MASSIVE UPDATE NUMBER ONE 2025-09-12 12:41:17 +10:00
Deserty0
782ae7c588 Update CP14FishBaseBehavior.cs 2025-09-11 03:07:27 +10:00
Deserty0
aa16b587fc Merge branch 'des-fishing' of https://github.com/crystallpunk-14/crystall-punk-14 into des-fishing 2025-09-11 01:14:46 +10:00
Deserty0
4de7747fb9 im actualy idk
ну шо ща пиздос
2025-09-11 01:14:20 +10:00
Deserty0
45f4668b11 Merge branch 'master' into des-fishing 2025-09-10 09:39:07 +10:00
Deserty0
5fbb8789df я опять невдупляю почему оно не работает продолжу завтра 2025-09-08 00:06:17 +10:00
Deserty0
c8b0560c7a UI 2025-09-07 04:31:11 +10:00
Deserty0
5d2fb2c4bc 13234546tyu 2025-09-07 01:37:52 +10:00
Deserty0
3759f240b3 123 2025-09-06 04:14:26 +10:00
Deserty0
af2e62ff59 я очень устал босс 2025-09-06 03:03:37 +10:00
Deserty0
307c0dc01b fix meta 2025-09-05 23:55:54 +10:00
Deserty0
0c44159c49 last work before silksong 2025-09-04 23:26:38 +10:00
Deserty0
dcecaded17 slow work 2025-09-04 22:54:20 +10:00
Deserty0
310126c660 init 2025-09-04 02:32:59 +10:00
326 changed files with 1530 additions and 840 deletions

38
.github/workflows/cla.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: "CLA Assistant"
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened,closed,synchronize]
paths:
- '**CP14**'
# explicitly configure permissions, in case your GITHUB_TOKEN workflow permissions are set to read-only in repository settings
permissions:
actions: write
contents: write # this can be 'read' if the signatures are in remote repository
pull-requests: write
statuses: write
jobs:
CLAAssistant:
runs-on: ubuntu-latest
steps:
- name: "CLA Assistant"
if: ((github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target') && github.actor != 'TheShuEd'
uses: contributor-assistant/github-action@v2.6.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret
# This token is required only if you have configured to store the signatures in a remote repository/organization
# PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
path-to-signatures: 'signatures/version1/cla.json'
path-to-document: 'https://github.com/crystallpunk-14/crystall-punk-14/blob/master/CLA.md' # e.g. a CLA or a DCO document
# branch should not be protected
branch: 'master'
allowlist: TheShuEd,bot*
# the followings are the optional inputs - If the optional inputs are not given, then default values will be taken
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'

View File

@@ -318,6 +318,7 @@ namespace Content.Client.Options.UI.Tabs
AddButton(CP14ContentKeyFunctions.CP14OpenSkillMenu);
AddButton(CP14ContentKeyFunctions.OpenBelt2);
AddButton(CP14ContentKeyFunctions.SmartEquipBelt2);
AddButton(CP14ContentKeyFunctions.CP14FishingAction);
//CP14 end
foreach (var control in _keyControls.Values)

View File

@@ -83,10 +83,6 @@ public sealed partial class ChatUIController : UIController
{SharedChatSystem.OOCPrefix, ChatSelectChannel.OOC},
{SharedChatSystem.EmotesPrefix, ChatSelectChannel.Emotes},
{SharedChatSystem.EmotesAltPrefix, ChatSelectChannel.Emotes},
// CrystallEdge alternative emotes prefix
{SharedChatSystem.CEEmotesPrefix, ChatSelectChannel.Emotes},
{SharedChatSystem.CEEmotesAltPrefix, ChatSelectChannel.Emotes},
// CrystallEdge End
{SharedChatSystem.AdminPrefix, ChatSelectChannel.Admin},
{SharedChatSystem.RadioCommonPrefix, ChatSelectChannel.Radio},
{SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead}

View File

@@ -0,0 +1,86 @@
using System.Diagnostics.CodeAnalysis;
using Content.Client.Hands.Systems;
using Content.Shared._CP14.Fishing;
using Content.Shared._CP14.Fishing.Components;
using Content.Shared._CP14.Input;
using Robust.Client.GameObjects;
using Robust.Shared.Input;
namespace Content.Client._CP14.Fishing;
public sealed class CP14FishingSystem : CP14SharedFishingSystem
{
[Dependency] private readonly InputSystem _input = default!;
[Dependency] private readonly HandsSystem _hands = default!;
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14FishingRodComponent, AfterAutoHandleStateEvent>(OnFishingRodState);
}
public override void Update(float dt)
{
base.Update(dt);
var heldUid = _hands.GetActiveHandEntity();
if (!TryComp<CP14FishingRodComponent>(heldUid, out var fishingRodComponent))
return;
UpdatePressedButtons(fishingRodComponent);
}
/// <summary>
/// Handles BUI updates
/// </summary>
private void OnFishingRodState(Entity<CP14FishingRodComponent> entity, ref AfterAutoHandleStateEvent args)
{
if (_userInterface.TryGetOpenUi(entity.Owner, CP14FishingUiKey.Key, out var bui))
{
bui.Update();
}
}
/// <summary>
/// Handles user inputs
/// </summary>
private void UpdatePressedButtons(CP14FishingRodComponent fishingRodComponent)
{
if (fishingRodComponent.CaughtFish is null)
return;
var reelKey = _input.CmdStates.GetState(CP14ContentKeyFunctions.CP14FishingAction) == BoundKeyState.Down;
if (fishingRodComponent.Reeling == reelKey)
return;
fishingRodComponent.Reeling = reelKey;
RaiseNetworkEvent(new CP14FishingReelKeyMessage(reelKey));
}
/// <summary>
/// Used to get fish and rod component by FishingUI
/// </summary>
/// <returns>True when all info can be resolved</returns>
public bool GetInfo([NotNullWhen(true)] out CP14FishingRodComponent? rodComponent,
[NotNullWhen(true)] out CP14FishComponent? fishComponent)
{
rodComponent = null;
fishComponent = null;
var heldUid = _hands.GetActiveHandEntity();
if (!TryComp<CP14FishingRodComponent>(heldUid, out var posRodComponent))
return false;
if (!TryComp<CP14FishComponent>(posRodComponent.CaughtFish, out var posFishComponent))
return false;
rodComponent = posRodComponent;
fishComponent = posFishComponent;
return true;
}
}

View File

@@ -0,0 +1,40 @@
using Content.Shared._CP14.Fishing.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
namespace Content.Client._CP14.Fishing.UI;
[UsedImplicitly]
public sealed class CP14FishingBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[ViewVariables]
private CP14FishingWindow? _fishingWindow;
public CP14FishingBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
if (!EntMan.TryGetComponent<CP14FishingRodComponent>(Owner, out var rodComponent))
return;
if (!_prototypeManager.Resolve(rodComponent.FishingMinigame, out var fishingMinigame))
return;
_fishingWindow = this.CreateWindow<CP14FishingWindow>();
_fishingWindow.InitVisuals(fishingMinigame);
}
public override void Update()
{
base.Update();
_fishingWindow?.UpdateDraw();
}
}

View File

@@ -0,0 +1,7 @@
<!-- Empty fishing popup -->
<fishingWindow:CP14FishingWindow
xmlns="https://spacestation14.io"
xmlns:fishingWindow="clr-namespace:Content.Client._CP14.Fishing.UI"
Name="FishingWindow" MaxSize="0 0">
<PanelContainer Name="FishingBackground"></PanelContainer>
</fishingWindow:CP14FishingWindow>

View File

@@ -0,0 +1,85 @@
using Content.Client.Resources;
using Content.Shared._CP14.Fishing;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client._CP14.Fishing.UI;
[GenerateTypedNameReferences]
public sealed partial class CP14FishingWindow : BaseWindow
{
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IEntityManager _entity = default!;
private readonly CP14FishingSystem _fishing;
private CP14FishingMinigamePrototype? _fishingMinigame;
private Texture? _floatTexture;
private Texture? _fishTexture;
public CP14FishingWindow()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
_fishing = _entity.System<CP14FishingSystem>();
}
public void InitVisuals(CP14FishingMinigamePrototype fishingMinigame)
{
FishingWindow.Visible = false;
// Hashing
_fishingMinigame = fishingMinigame;
// Getting data
var background = _fishingMinigame.Background;
var fish = _fishingMinigame.FishIcon;
var floater = _fishingMinigame.Float;
FishingWindow.MaxSize = background.Size;
FishingWindow.SetSize = background.Size;
FishingBackground.SetSize = background.Size;
var backgroundTexture = _resourceCache.GetTexture(background.Texture);
FishingBackground.PanelOverride = new StyleBoxTexture
{
Texture = backgroundTexture,
};
_floatTexture = _resourceCache.GetTexture(floater.Texture);
_fishTexture = _resourceCache.GetTexture(fish.Texture);
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (_fishingMinigame is null || _floatTexture is null || _fishTexture is null)
return;
if (!_fishing.GetInfo(out var rodComponent, out var fishComponent))
return;
var floatBox = CalculateUIBox(_fishingMinigame.Float, rodComponent.FloatPosition);
var fishBox = CalculateUIBox(_fishingMinigame.FishIcon, fishComponent.Position);
handle.DrawTextureRect(_floatTexture, floatBox);
handle.DrawTextureRect(_fishTexture, fishBox);
}
private static UIBox2 CalculateUIBox(FishingMinigameElementData data, float verticalOffset)
{
var left = data.Offset.X;
var top = data.Offset.Y + verticalOffset + data.Size.Y;
var right = data.Offset.X + data.Size.X;
var bottom = data.Offset.Y + verticalOffset;
return new UIBox2(left, top, right, bottom);
}
}

View File

@@ -11,6 +11,7 @@ namespace Content.Client._CP14.Input
human.AddFunction(CP14ContentKeyFunctions.OpenBelt2);
human.AddFunction(CP14ContentKeyFunctions.SmartEquipBelt2);
human.AddFunction(CP14ContentKeyFunctions.CP14OpenSkillMenu);
human.AddFunction(CP14ContentKeyFunctions.CP14FishingAction);
}
}
}

View File

@@ -1,7 +1,6 @@
using System.Numerics;
using Content.Shared._CP14.MagicVision;
using Content.Shared.Examine;
using Content.Shared.StatusEffectNew;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
@@ -22,16 +21,14 @@ public sealed class CP14ClientMagicVisionSystem : CP14SharedMagicVisionSystem
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StatusEffectsSystem _status = default!;
private CP14MagicVisionOverlay? _overlay;
private CP14MagicVisionNoirOverlay? _overlay2;
private TimeSpan _nextUpdate = TimeSpan.Zero;
private readonly SoundSpecifier _startSound = new SoundPathSpecifier(new ResPath("/Audio/Effects/eye_open.ogg"));
private readonly SoundSpecifier _endSound = new SoundPathSpecifier(new ResPath("/Audio/Effects/eye_close.ogg"));
private SoundSpecifier _startSound = new SoundPathSpecifier(new ResPath("/Audio/Effects/eye_open.ogg"));
private SoundSpecifier _endSound = new SoundPathSpecifier(new ResPath("/Audio/Effects/eye_close.ogg"));
public override void Initialize()
{
@@ -39,52 +36,71 @@ public sealed class CP14ClientMagicVisionSystem : CP14SharedMagicVisionSystem
SubscribeLocalEvent<CP14MagicVisionMarkerComponent, AfterAutoHandleStateEvent>(OnHandleStateMarker);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerAttachedEvent>>(OnPlayerAttached);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerDetachedEvent>>(OnPlayerDetached);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectAppliedEvent>(OnStatusEffectApplied);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRemovedEvent>(OnStatusEffectRemoved);
SubscribeLocalEvent<CP14MagicVisionComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<CP14MagicVisionComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<CP14MagicVisionComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<CP14MagicVisionComponent, ComponentShutdown>(OnComponentShutdown);
}
private void OnPlayerAttached(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
private void OnComponentShutdown(Entity<CP14MagicVisionComponent> ent, ref ComponentShutdown args)
{
if (args.Args.Entity != _player.LocalEntity)
if (_player.LocalEntity != ent)
return;
if (_overlay != null)
{
_overlayMan.RemoveOverlay(_overlay);
_overlay = null;
}
if (_overlay2 != null)
{
_overlayMan.RemoveOverlay(_overlay2);
_overlay2 = null;
}
ApplyOverlay(ent);
_audio.PlayGlobal(_endSound, ent);
}
private void OnStatusEffectApplied(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
private void OnComponentInit(Entity<CP14MagicVisionComponent> ent, ref ComponentInit args)
{
if (args.Target != _player.LocalEntity)
if (_player.LocalEntity != ent)
return;
//Prevents it from being applied twice
if (_timing.IsFirstTimePredicted)
return;
_overlay = new CP14MagicVisionOverlay();
_overlayMan.AddOverlay(_overlay);
_overlay.StartOverlay = _timing.CurTime;
ApplyOverlay(ent);
_overlay2 = new CP14MagicVisionNoirOverlay();
_overlayMan.AddOverlay(_overlay2);
_audio.PlayGlobal(_startSound, ent);
}
private void OnPlayerDetached(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
private void OnPlayerAttached(Entity<CP14MagicVisionComponent> ent, ref LocalPlayerAttachedEvent args)
{
if (args.Args.Entity != _player.LocalEntity)
return;
_overlay = new CP14MagicVisionOverlay();
_overlayMan.AddOverlay(_overlay);
_overlay.StartOverlay = _timing.CurTime;
RemoveOverlay(ent);
_overlay2 = new CP14MagicVisionNoirOverlay();
_overlayMan.AddOverlay(_overlay2);
_audio.PlayGlobal(_startSound, ent);
}
private void OnStatusEffectRemoved(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
private void OnPlayerDetached(Entity<CP14MagicVisionComponent> ent, ref LocalPlayerDetachedEvent args)
{
if (args.Target != _player.LocalEntity)
return;
//Prevents it from beeing removed twice
if (_timing.IsFirstTimePredicted)
return;
RemoveOverlay(ent);
if (_overlay != null)
{
_overlayMan.RemoveOverlay(_overlay);
_overlay = null;
}
if (_overlay2 != null)
{
_overlayMan.RemoveOverlay(_overlay2);
_overlay2 = null;
}
_audio.PlayGlobal(_endSound, ent);
}
protected override void OnExamined(Entity<CP14MagicVisionMarkerComponent> ent, ref ExaminedEvent args)
@@ -138,38 +154,6 @@ public sealed class CP14ClientMagicVisionSystem : CP14SharedMagicVisionSystem
{
var progress = Math.Clamp((_timing.CurTime.TotalSeconds - ent.Comp.SpawnTime.TotalSeconds) / (ent.Comp.EndTime.TotalSeconds - ent.Comp.SpawnTime.TotalSeconds), 0, 1);
var alpha = 1 - progress;
_sprite.SetColor((ent.Owner, sprite), Color.White.WithAlpha((float)alpha));
}
private void ApplyOverlay(Entity<CP14MagicVisionStatusEffectComponent> ent)
{
_overlay = new CP14MagicVisionOverlay();
_overlayMan.AddOverlay(_overlay);
_overlay.StartOverlay = _timing.CurTime;
_overlay2 = new CP14MagicVisionNoirOverlay();
_overlayMan.AddOverlay(_overlay2);
_audio.PlayGlobal(_startSound, ent);
}
private void RemoveOverlay(Entity<CP14MagicVisionStatusEffectComponent> ent)
{
// Check if it is the last Magic Vision Status Effect
if (_status.HasEffectComp<CP14MagicVisionStatusEffectComponent>(_player.LocalEntity))
return;
if (_overlay != null)
{
_overlayMan.RemoveOverlay(_overlay);
_overlay = null;
}
if (_overlay2 != null)
{
_overlayMan.RemoveOverlay(_overlay2);
_overlay2 = null;
}
_audio.PlayGlobal(_endSound, ent);
_sprite.SetColor(ent.Owner, Color.White.WithAlpha((float)alpha));
}
}

View File

@@ -44,6 +44,9 @@ public sealed class CP14MagicVisionOverlay : Overlay
if (playerEntity == null)
return;
if (!_entityManager.HasComponent<CP14MagicVisionComponent>(playerEntity))
return;
var curTime = _timing.CurTime;
var timeLeft = (float)(curTime - StartOverlay).TotalSeconds;

View File

@@ -0,0 +1,122 @@
using System.Linq;
using System.Numerics;
using Content.Shared._CP14.Fishing;
using Content.Shared._CP14.Fishing.Components;
using Content.Shared.EntityTable;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Server.Player;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._CP14.Fishing;
public sealed class CP14FishingSystem : CP14SharedFishingSystem
{
[Dependency] private readonly EntityTableSystem _entityTable = default!;
[Dependency] private readonly MetaDataSystem _meta = default!;
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly PvsOverrideSystem _pvs= default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
private MapId? _mapId;
private EntityQuery<CP14FishingPondComponent> _pondQuery;
private EntityQuery<CP14FishComponent> _fishQuery;
public override void Initialize()
{
base.Initialize();
_pondQuery = GetEntityQuery<CP14FishingPondComponent>();
_fishQuery = GetEntityQuery<CP14FishComponent>();
}
public override void Update(float frameTime)
{
base.Update(frameTime);
base.Update(frameTime);
var curTime = _gameTiming.CurTime;
var query = EntityQueryEnumerator<CP14FishingRodComponent>();
// Seeding prediction doesnt work
while (query.MoveNext(out var uid, out var fishRod))
{
TryToCatchFish((uid, fishRod), curTime);
}
}
/// <summary>
/// Tries to cath fish
/// </summary>
private bool TryToCatchFish(Entity<CP14FishingRodComponent> rod, TimeSpan curTime)
{
if (rod.Comp.CaughtFish is not null)
return false;
if (rod.Comp.User is null)
return false;
if (rod.Comp.FishingFloat is null)
return false;
if (rod.Comp.Target is null)
return false;
if (curTime < rod.Comp.FishingTime)
return false;
var pond = rod.Comp.Target;
if (!_pondQuery.TryComp(pond, out var pondComp))
return false;
if (pondComp.LootTable is null)
return false;
if (!_proto.Resolve(pondComp.LootTable, out var lootTable))
return false;
var fishes = _entityTable.GetSpawns(lootTable, _random.GetRandom());
var fishId = fishes.First();
EnsurePausedMap();
var fish = PredictedSpawnAtPosition(fishId, new EntityCoordinates(_map.GetMap(_mapId!.Value), Vector2.Zero));
if (!_player.TryGetSessionByEntity(rod.Comp.User.Value, out var session))
return false;
if (!_fishQuery.TryComp(fish, out var fishComp))
return false;
_pvs.AddSessionOverride(fish, session);
rod.Comp.CaughtFish = fish;
fishComp.GetAwayTime = curTime;
fishComp.GetAwayTime += TimeSpan.FromSeconds(_random.NextDouble(rod.Comp.MinAwaitTime, rod.Comp.MaxAwaitTime));
DirtyField(rod, rod.Comp, nameof(CP14FishingRodComponent.CaughtFish));
DirtyField(fish, fishComp, nameof(CP14FishComponent.GetAwayTime));
return true;
}
/// <summary>
/// Ensures that paused map exists
/// </summary>
private void EnsurePausedMap()
{
if (_map.MapExists(_mapId))
return;
var mapUid = _map.CreateMap(out var newMapId);
_meta.SetEntityName(mapUid, Loc.GetString("fishing-paused-map-name"));
_mapId = newMapId;
_map.SetPaused(mapUid, true);
}
}

View File

@@ -1,6 +1,6 @@
using Content.Shared._CP14.MagicVision;
using Content.Shared.Eye;
using Robust.Shared.Timing;
using Content.Shared.StatusEffectNew;
namespace Content.Server._CP14.MagicVision;
@@ -13,19 +13,26 @@ public sealed class CP14MagicVisionSystem : CP14SharedMagicVisionSystem
{
base.Initialize();
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRelayedEvent<GetVisMaskEvent>>(OnGetVisMask);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectAppliedEvent>(OnApplied);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRemovedEvent>(OnRemoved);
SubscribeLocalEvent<MetaDataComponent, CP14MagicVisionToggleActionEvent>(OnMagicVisionToggle);
SubscribeLocalEvent<CP14MagicVisionComponent, GetVisMaskEvent>(OnGetVisMask);
}
private void OnGetVisMask(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRelayedEvent<GetVisMaskEvent> args)
private void OnGetVisMask(Entity<CP14MagicVisionComponent> ent, ref GetVisMaskEvent args)
{
var appliedMask = (int)CP14MagicVisionStatusEffectComponent.VisibilityMask;
var newArgs = args.Args;
args.VisibilityMask |= (int)VisibilityFlags.CP14MagicVision;
}
newArgs.VisibilityMask |= appliedMask;
args = args with { Args = newArgs };
private void OnMagicVisionToggle(Entity<MetaDataComponent> ent, ref CP14MagicVisionToggleActionEvent args)
{
if (!HasComp<CP14MagicVisionComponent>(ent))
{
AddComp<CP14MagicVisionComponent>(ent);
}
else
{
RemComp<CP14MagicVisionComponent>(ent);
}
_eye.RefreshVisibilityMask(ent.Owner);
}
public override void Update(float frameTime)
@@ -44,14 +51,4 @@ public sealed class CP14MagicVisionSystem : CP14SharedMagicVisionSystem
QueueDel(uid);
}
}
private void OnApplied(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
{
_eye.RefreshVisibilityMask(args.Target);
}
private void OnRemoved(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
{
_eye.RefreshVisibilityMask(args.Target);
}
}

View File

@@ -1,38 +0,0 @@
using Content.Shared._CP14.StatusEffect;
using Content.Shared.StatusEffectNew;
using Content.Shared.StatusEffectNew.Components;
using Robust.Shared.Timing;
namespace Content.Server._CP14.StatusEffect;
public sealed partial class CP14EntityEffectsStatusEffectSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly EntityManager _entityManager = default!;
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<CP14EntityEffectsStatusEffectComponent, StatusEffectComponent>();
while (query.MoveNext(out var ent, out var entityEffect, out var statusEffect))
{
if (entityEffect.NextUpdateTime > _timing.CurTime)
continue;
if (statusEffect.AppliedTo is not EntityUid targetUid)
continue;
entityEffect.NextUpdateTime = _timing.CurTime + entityEffect.Frequency;
foreach (var effect in entityEffect.Effects)
{
//Apply Effect on target
effect.Effect(new(targetUid, _entityManager));
}
}
}
public override void Initialize()
{
base.Initialize();
}
}

View File

@@ -1,29 +0,0 @@
using Content.Shared.EntityEffects;
namespace Content.Server._CP14.StatusEffect;
/// <summary>
/// Applies Entity Effects at a given frequency
/// </summary>
[RegisterComponent, AutoGenerateComponentState, Access(typeof(CP14EntityEffectsStatusEffectSystem))]
public sealed partial class CP14EntityEffectsStatusEffectComponent : Component
{
/// <summary>
/// List of Effects that will be applied
/// </summary>
[DataField]
public List<EntityEffect> Effects = [];
/// <summary>
/// How often objects will try to apply <see cref="Effects"/>. In Seconds.
/// </summary>
[DataField]
public TimeSpan Frequency = TimeSpan.FromSeconds(5);
/// <summary>
/// The time of the next Effect trigger
/// </summary>
[DataField]
public TimeSpan NextUpdateTime { get; set; } = TimeSpan.Zero;
}

View File

@@ -24,10 +24,6 @@ public abstract class SharedChatSystem : EntitySystem
public const char AdminPrefix = ']';
public const char WhisperPrefix = ',';
public const char DefaultChannelKey = 'h';
// CrystallEdge # and % emotes prefix
public const char CEEmotesPrefix = '%';
public const char CEEmotesAltPrefix = '#';
// CrystallEdge End
public const int VoiceRange = 10; // how far voice goes in world units
public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units

View File

@@ -7,7 +7,6 @@ using Content.Shared.Speech;
using Content.Shared.StatusEffectNew.Components;
using Content.Shared.Stunnable;
using Robust.Shared.Player;
using Content.Shared.Mobs;
namespace Content.Shared.StatusEffectNew;
@@ -17,8 +16,6 @@ public sealed partial class StatusEffectsSystem
{
//CP14 Zone
SubscribeLocalEvent<StatusEffectContainerComponent, DamageModifyEvent>(RelayStatusEffectEvent);
SubscribeLocalEvent<StatusEffectContainerComponent, GetVisMaskEvent>(RefRelayStatusEffectEvent);
SubscribeLocalEvent<StatusEffectContainerComponent, MobStateChangedEvent>(RefRelayStatusEffectEvent);
//CP14 Zone end
SubscribeLocalEvent<StatusEffectContainerComponent, LocalPlayerAttachedEvent>(RelayStatusEffectEvent);

View File

@@ -0,0 +1,46 @@
using JetBrains.Annotations;
using Robust.Shared.Random;
namespace Content.Shared._CP14.Fishing.Behaviors;
[ImplicitDataDefinitionForInheritors, UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public abstract partial class CP14FishBaseBehavior
{
/// <summary>
/// Calculates fish position
/// </summary>
/// <param name="random"> Robust random interface </param>
/// <param name="fishPos"> Current position of fish </param>
/// <param name="fishDest"> Fish destination </param>
/// <returns> Calculated fish position </returns>
public float TryCalculatePosition(IRobustRandom random, float fishPos, float fishDest)
{
var speed = CalculateSpeed(random);
var nextPos = float.Lerp(fishPos, fishDest, speed);
return nextPos;
}
/// <summary>
/// Formula to calculate fish speed
/// </summary>
public abstract float CalculateSpeed(IRobustRandom random);
/// <summary>
/// Speed of a fish
/// </summary>
[DataField]
public float Speed = 0.25f;
/// <summary>
/// Salt of speed calculations
/// </summary>
[DataField]
public float Difficulty = 2f;
/// <summary>
/// Base time which fish will wait in destination before selecting new
/// </summary>
[DataField]
public TimeSpan BaseWaitTime = TimeSpan.FromSeconds(5);
}

View File

@@ -0,0 +1,11 @@
using Robust.Shared.Random;
namespace Content.Shared._CP14.Fishing.Behaviors;
public sealed partial class CP14FishDartBehaviour : CP14FishBaseBehavior
{
public override float CalculateSpeed(IRobustRandom random)
{
return Speed * (0.5f + random.NextFloat() * Difficulty);
}
}

View File

@@ -0,0 +1,64 @@
using System.Numerics;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Fishing;
/// <summary>
/// Prototype of fishing minigame. Starter position of minigame in the bottom
/// </summary>
[Prototype("CP14FishingMinigameStyle")]
public sealed class CP14FishingMinigamePrototype : IPrototype
{
[IdDataField]
public string ID { get; } = default!;
/// <summary>
/// Fishing minigame background data
/// </summary>
[DataField(required: true)]
public FishingMinigameElementData Background;
/// <summary>
/// Fishing minigame fish icon data
/// </summary>
[DataField(required: true)]
public FishingMinigameElementData FishIcon;
/// <summary>
/// Fishing minigame progressbar data
/// </summary>
[DataField(required: true)]
public FishingMinigameElementData Progressbar;
/// <summary>
/// Fishing minigame float data
/// </summary>
[DataField(required: true)]
public FishingMinigameElementData Float;
/// <summary>
/// Size of the area where the float and fish will move
/// </summary>
[DataField(required: true)]
public float FishingMinigameSize;
}
[DataDefinition]
public partial struct FishingMinigameElementData
{
/// <summary>
/// Texture path
/// </summary>
[DataField(required: true)] public ResPath Texture;
/// <summary>
/// Size of a texture
/// </summary>
[DataField(required: true)] public Vector2 Size;
/// <summary>
/// Offset from bottom left corner
/// </summary>
[DataField(required: true)] public Vector2 Offset;
}

View File

@@ -0,0 +1,21 @@
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.Fishing;
/// <summary>
/// Key for CP14FishingBoundUserInterface
/// </summary>
[Serializable, NetSerializable]
public enum CP14FishingUiKey : byte
{
Key,
}
/// <summary>
/// Event for sending reeling key status
/// </summary>
[Serializable, NetSerializable]
public sealed class CP14FishingReelKeyMessage(bool reeling) : EntityEventArgs
{
public bool Reeling = reeling;
}

View File

@@ -0,0 +1,278 @@
using Content.Shared._CP14.Fishing.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Throwing;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Shared._CP14.Fishing;
public abstract class CP14SharedFishingSystem : EntitySystem
{
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
[Dependency] private readonly SharedUserInterfaceSystem _userInterface = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
private EntityQuery<CP14FishComponent> _fishQuery;
public override void Initialize()
{
base.Initialize();
_fishQuery = GetEntityQuery<CP14FishComponent>();
SubscribeLocalEvent<CP14FishingRodComponent, AfterInteractEvent>(OnInteract);
SubscribeLocalEvent<CP14FishingRodComponent, DroppedEvent>(OnDropEvent);
SubscribeNetworkEvent<CP14FishingReelKeyMessage>(OnReelingMessage);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var curTime = _gameTiming.CurTime;
var query = EntityQueryEnumerator<CP14FishingRodComponent>();
// Seeding prediction doesnt work
while (query.MoveNext(out var uid, out var fishRod))
{
if (fishRod.User is null)
continue;
RevalidateFishing((uid, fishRod));
if (fishRod.User is null)
continue;
if (fishRod.FishingFloat is null)
continue;
if (fishRod.Target is null)
continue;
var fish = fishRod.CaughtFish;
if (fishRod.CaughtFish is not null && _fishQuery.TryComp(fish, out var fishComp)) //TODO: remove multiple fish TryComp in next functions
continue;
_random.SetSeed((int)_gameTiming.CurTick.Value + GetNetEntity(uid).Id);
UpdateFishWaitingStatus((uid, fishRod), curTime);
UpdatePositions((uid, fishRod), curTime);
}
}
/// <summary>
/// Handles float and fish positions updates
/// </summary>
/// <remarks> Please burn it down </remarks>
private void UpdatePositions(Entity<CP14FishingRodComponent> rod, TimeSpan curTime)
{
if (rod.Comp.CaughtFish is null)
return;
if (!rod.Comp.FishHooked)
return;
var fish = rod.Comp.CaughtFish;
if (!_fishQuery.TryComp(fish, out var fishComp))
return;
_proto.Resolve(rod.Comp.FishingMinigame, out var minigamePrototype);
if (minigamePrototype is null)
return;
var maxCord = minigamePrototype.FishingMinigameSize;
var floatSpeed = rod.Comp.FloatSpeed;
var floatPosition = rod.Comp.FloatPosition;
if (rod.Comp.Reeling)
{
Math.Clamp(floatPosition + floatSpeed, 0, maxCord);
}
else
{
Math.Clamp(floatPosition - floatSpeed, 0, maxCord);
}
var fishPos = fishComp.Position;
var fishDest = fishComp.Destination;
var fishBaseWaitTime = fishComp.Behavior.BaseWaitTime;
if (Math.Abs(fishPos - fishDest) < 0.1f)
{
UpdateFishDestination((fish.Value, fishComp), curTime, maxCord);
fishComp.SelectPosTime = curTime + fishBaseWaitTime + fishBaseWaitTime * 0.2 * _random.NextFloat(-1, 1);
}
else
{
fishComp.Position = fishComp.Behavior.TryCalculatePosition(_random, fishComp.Position, fishComp.Destination);
}
DirtyField(rod, rod.Comp, nameof(CP14FishingRodComponent.FloatPosition));
DirtyField(fish.Value, fishComp, nameof(CP14FishComponent.Position));
}
/// <summary>
/// Calculates new fish destination
/// </summary>
private void UpdateFishDestination(Entity<CP14FishComponent> fish, TimeSpan curTime, float maxCord)
{
if (curTime < fish.Comp.SelectPosTime)
return;
fish.Comp.Destination = _random.NextFloat(0, maxCord);
DirtyField(fish, fish.Comp, nameof(CP14FishComponent.Destination));
}
/// <summary>
/// Handles if fish got caught or flees
/// </summary>
private void UpdateFishWaitingStatus(Entity<CP14FishingRodComponent> rod, TimeSpan curTime)
{
if (rod.Comp.CaughtFish is null)
return;
if (rod.Comp.FishHooked)
return;
if (rod.Comp.User is null)
return;
var fish = rod.Comp.CaughtFish;
if (!_fishQuery.TryComp(fish, out var fishComp))
return;
if (rod.Comp.Reeling)
{
rod.Comp.FishHooked = true;
_userInterface.TryOpenUi(rod.Owner, CP14FishingUiKey.Key, rod.Comp.User.Value);
DirtyField(rod, rod.Comp, nameof(CP14FishingRodComponent.FishHooked));
return;
}
if (curTime < fishComp.GetAwayTime)
return;
rod.Comp.CaughtFish = null;
DirtyField(rod, rod.Comp, nameof(CP14FishingRodComponent.CaughtFish));
PredictedDel(fish);
}
/// <summary>
/// Validates if user is still in range of fishing float
/// </summary>
private void RevalidateFishing(Entity<CP14FishingRodComponent> rod)
{
if (rod.Comp.FishingFloat is null)
return;
if (_transform.InRange(rod.Owner, rod.Comp.FishingFloat.Value, rod.Comp.MaxFishingDistance * 1.5f))
return;
PredictedDel(rod.Comp.FishingFloat);
rod.Comp.FishHooked = false;
rod.Comp.CaughtFish = null;
rod.Comp.FishingFloat = null;
rod.Comp.Target = null;
rod.Comp.User = null;
DirtyFields(rod,
rod.Comp,
null,
nameof(CP14FishingRodComponent.FishingFloat),
nameof(CP14FishingRodComponent.Target),
nameof(CP14FishingRodComponent.User),
nameof(CP14FishingRodComponent.CaughtFish),
nameof(CP14FishingRodComponent.FishHooked));
}
/// <summary>
/// Sets <see cref="CP14FishingRodComponent.Reeling"/> to user button status
/// </summary>
private void OnReelingMessage(CP14FishingReelKeyMessage msg, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity is not { } player)
return;
if (!_hands.TryGetActiveItem(player, out var activeItem) ||
!TryComp<CP14FishingRodComponent>(activeItem, out var fishingRodComponent))
return;
fishingRodComponent.Reeling = msg.Reeling;
DirtyField(activeItem.Value, fishingRodComponent, nameof(CP14FishingRodComponent.Reeling));
}
/// <summary>
/// Starts new fishing process when user interacts with pond using fishing rod
/// </summary>
private void OnInteract(Entity<CP14FishingRodComponent> rod, ref AfterInteractEvent args)
{
if (args.Handled)
return;
if (args.Target is not { Valid: true })
return;
if (rod.Comp.FishingFloat is not null)
return;
if (!TryComp<CP14FishingPondComponent>(args.Target, out _))
return;
if (!_interaction.InRangeUnobstructed(rod.Owner, args.Target.Value, rod.Comp.MaxFishingDistance))
return;
args.Handled = true;
rod.Comp.FishingTime = _gameTiming.CurTime;
rod.Comp.FishingTime += TimeSpan.FromSeconds(_random.NextDouble(rod.Comp.MinAwaitTime, rod.Comp.MaxAwaitTime));
rod.Comp.User = args.User;
DirtyFields(rod, rod.Comp, null, nameof(CP14FishingRodComponent.FishingTime), nameof(CP14FishingRodComponent.User));
ThrowFishingFloat(rod, args.Target.Value);
}
/// <summary>
/// Deletes <see cref="CP14FishingRodComponent.User"/> link
/// </summary>
private void OnDropEvent(Entity<CP14FishingRodComponent> rod, ref DroppedEvent args)
{
rod.Comp.User = null;
DirtyField(rod, rod.Comp, nameof(CP14FishingRodComponent.User));
}
/// <summary>
/// Spawns and throws fishing float
/// </summary>
private void ThrowFishingFloat(Entity<CP14FishingRodComponent> rod, EntityUid fishingPond)
{
var rodCoords = Transform(rod).Coordinates;
var targetCoords = Transform(fishingPond).Coordinates;
var fishingFloat = PredictedSpawnAtPosition(rod.Comp.FloatPrototype, rodCoords);
rod.Comp.FishingFloat = fishingFloat;
rod.Comp.Target = fishingPond;
DirtyFields(rod,
rod.Comp,
null,
nameof(CP14FishingRodComponent.FishingFloat),
nameof(CP14FishingRodComponent.Target));
_throwing.TryThrow(fishingFloat, targetCoords, rod.Comp.ThrowPower, recoil: false, doSpin: false);
}
}

View File

@@ -0,0 +1,53 @@
using Content.Shared._CP14.Fishing.Behaviors;
using Robust.Shared.GameStates;
namespace Content.Shared._CP14.Fishing.Components;
/// <summary>
/// Component for fish, that can be caught via fishing
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause, Access(typeof(CP14SharedFishingSystem))]
public sealed partial class CP14FishComponent : Component
{
/// <summary>
/// Fish behaviour that will be used for speed calculations
/// </summary>
[DataField(required: true), ViewVariables]
public CP14FishBaseBehavior Behavior;
/// <summary>
/// Time when fish will select next position
/// </summary>
[AutoNetworkedField, AutoPausedField, ViewVariables]
public TimeSpan SelectPosTime = TimeSpan.Zero;
/// <summary>
/// Time when the fish will get away if it is not hooked
/// </summary>
[AutoNetworkedField, AutoPausedField, ViewVariables]
public TimeSpan GetAwayTime = TimeSpan.Zero;
/// <summary>
/// Fish current position in minigame coordinates
/// </summary>
[AutoNetworkedField, ViewVariables]
public float Position;
/// <summary>
/// Fish destination in minigame coordinates
/// </summary>
[AutoNetworkedField, ViewVariables]
public float Destination;
/// <summary>
/// Minimal time before fish will get away
/// </summary>
[DataField]
public double MinAwaitTime = 5;
/// <summary>
/// Maximum time before fish will get away
/// </summary>
[DataField]
public double MaxAwaitTime = 10;
}

View File

@@ -0,0 +1,18 @@
using Content.Shared.EntityTable;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Fishing.Components;
/// <summary>
/// Component for fishing ponds
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(CP14SharedFishingSystem))]
public sealed partial class CP14FishingPondComponent : Component
{
/// <summary>
/// LootTable of loot that can be caught in this pond. Only first spawn will be caught
/// </summary>
[DataField]
public ProtoId<EntityTablePrototype>? LootTable;
}

View File

@@ -0,0 +1,105 @@
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Fishing.Components;
/// <summary>
/// Allows to fish with this item
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true, true), AutoGenerateComponentPause, Access(typeof(CP14SharedFishingSystem))]
public sealed partial class CP14FishingRodComponent : Component
{
// Vars
/// <summary>
/// Link to a fishing float, attached to rod
/// </summary>
[AutoNetworkedField, ViewVariables]
public EntityUid? FishingFloat;
/// <summary>
/// Link to fishing rod user
/// </summary>
[AutoNetworkedField, ViewVariables]
public EntityUid? User;
/// <summary>
/// Link to caught fish
/// </summary>
[AutoNetworkedField, ViewVariables]
public EntityUid? CaughtFish;
/// <summary>
/// Link to a target fishing pond
/// </summary>
[AutoNetworkedField, ViewVariables]
public EntityUid? Target;
/// <summary>
/// Float position in minigame coordinates
/// </summary>
[AutoNetworkedField, ViewVariables]
public float FloatPosition = 0f;
/// <summary>
/// Time when fish will be caught
/// </summary>
[AutoNetworkedField, AutoPausedField, ViewVariables]
public TimeSpan FishingTime = TimeSpan.Zero;
/// <summary>
/// Does the user pull the fishing line
/// </summary>
[AutoNetworkedField, ViewVariables]
public bool Reeling;
/// <summary>
/// Is fish hooked
/// </summary>
[AutoNetworkedField, ViewVariables]
public bool FishHooked;
// Data definitions
/// <summary>
/// Fishing float prototype
/// </summary>
[DataField]
public EntProtoId FloatPrototype = "CP14DefaultFishingFloat";
/// <summary>
/// Fishing minigame prototype
/// </summary>
[DataField]
public ProtoId<CP14FishingMinigamePrototype> FishingMinigame = "Default";
/// <summary>
/// Speed of a float in minigame coordinates
/// </summary>
[DataField]
public float FloatSpeed = 2f;
/// <summary>
/// Max distance between rod and float
/// </summary>
[DataField]
public float MaxFishingDistance = 5f;
/// <summary>
/// Power with which float will be thrown
/// </summary>
[DataField]
public float ThrowPower = 10f;
/// <summary>
/// Minimal time before fish will be caught
/// </summary>
[DataField]
public double MinAwaitTime = 5;
/// <summary>
/// Maximum time before fish will be caught
/// </summary>
[DataField]
public double MaxAwaitTime = 20;
}

View File

@@ -9,5 +9,6 @@ namespace Content.Shared._CP14.Input
public static readonly BoundKeyFunction OpenBelt2 = "OpenBelt2";
public static readonly BoundKeyFunction SmartEquipBelt2 = "SmartEquipBelt2";
public static readonly BoundKeyFunction CP14OpenSkillMenu = "CP14OpenSkillMenu";
public static readonly BoundKeyFunction CP14FishingAction = "CP14FishingAction";
}
}
}

View File

@@ -1,24 +0,0 @@
using Content.Shared.StatusEffectNew;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.MagicSpell.Spells;
public sealed partial class CP14SpellToggleStatusEffect : CP14SpellEffect
{
[DataField(required: true)]
public EntProtoId StatusEffect = default;
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
{
if (args.Target is null)
return;
var effectSys = entManager.System<StatusEffectsSystem>();
if (!effectSys.HasStatusEffect(args.Target.Value, StatusEffect))
effectSys.TrySetStatusEffectDuration(args.Target.Value, StatusEffect);
else
effectSys.TryRemoveStatusEffect(args.Target.Value, StatusEffect);
}
}

View File

@@ -4,7 +4,6 @@ using Content.Shared._CP14.AuraDNA;
using Content.Shared._CP14.MagicVision.Components;
using Content.Shared.Actions;
using Content.Shared.Examine;
using Content.Shared.Mobs;
using Content.Shared.StatusEffectNew;
using Robust.Shared.Map;
using Robust.Shared.Network;
@@ -28,15 +27,6 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent<CP14MagicVisionMarkerComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRelayedEvent<MobStateChangedEvent>>(OnMobStateChange);
}
private void OnMobStateChange(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRelayedEvent<MobStateChangedEvent> args)
{
if (args.Args.NewMobState == MobState.Alive) return;
//Removes MagicVisionStatusEffect entity when MobState is Crit,Dead or Invalid
TryQueueDel(ent);
}
protected virtual void OnExamined(Entity<CP14MagicVisionMarkerComponent> ent, ref ExaminedEvent args)
@@ -158,3 +148,7 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem
Dirty(ent, markerComp);
}
}
public sealed partial class CP14MagicVisionToggleActionEvent : InstantActionEvent
{
}

View File

@@ -0,0 +1,11 @@
using Robust.Shared.GameStates;
namespace Content.Shared._CP14.MagicVision;
/// <summary>
/// Allows to see magic vision trace entities
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class CP14MagicVisionComponent : Component
{
}

View File

@@ -1,17 +0,0 @@
using Content.Shared.Eye;
using Robust.Shared.GameStates;
namespace Content.Shared._CP14.MagicVision;
/// <summary>
/// Allows to see magic vision trace entities
/// Use only in conjunction with <see cref="StatusEffectComponent"/>, on the status effect entity.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class CP14MagicVisionStatusEffectComponent : Component
{
/// <summary>
/// VisionMask to see Magic Vision layer
/// </summary>
public const VisibilityFlags VisibilityMask = VisibilityFlags.CP14MagicVision;
}

15
LICENSE_CE.TXT Normal file
View File

@@ -0,0 +1,15 @@
All rights reserved.
Copyright (c) 2025 CrystallEdge
This source code is the exclusive of TheShuEd and is protected by copyright law.
You granted no rights or permissions to use, modify, distribute, sublicense,
or reproduce this source code in any form, in whole or in part,
without the express written consent of TheShuEd.
Any unauthorized use or reproduction of this source code
is strictly prohibited and may result in legal action.
For inquiries or licensing requests,
please contact TheShuEd at Discord (https://discord.gg/Sud2DMfhCC).

View File

@@ -5,6 +5,10 @@ CrystallEdge is a build running on the [RobustToolbox](https://github.com/space-
## Links
[Discord](https://discord.gg/Sud2DMfhCC) | [Steam](https://store.steampowered.com/app/1255460/Space_Station_14/) | [Boosty](https://boosty.to/theshued)
## Contributing
We welcome any support from the community in the development of the game! Join our discord to find out how you can help the project, or check out [Issues](https://github.com/crystallpunk-14/crystall-punk-14/issues) on Github.
## Building
1. Clone this repo.
@@ -13,11 +17,13 @@ CrystallEdge is a build running on the [RobustToolbox](https://github.com/space-
[More detailed instructions on building the project.](https://docs.spacestation14.com/en/general-development/setup.html)
## License
## Licensing/Attriibution
All code for the content repository is licensed under the [MIT license](https://github.com/crystallpunk-14/crystall-punk-14/blob/master/LICENSE.TXT).
These are just the most important points, Please read [Legal.md](https://github.com/crystallpunk-14/crystall-punk-14/blob/master/Legal.md) for the specifics around licensing/attribution/copyright.
- Unless specified otherwise, all Source Code, inside any _CP14 or CP14 folders, fall under the terms specified in LICENSE_CE.TXT (all right reserved) with Exhibit B enforced and the CrystallEdge CLA. All assets/content in those folders falls under CC-BY-SA 4.0 unless otherwise specified.
- Any content from SpaceWizards/SpaceStation14 without specified licensing of any code is licensed under MIT (LICENSE.txt). Any Space Wizards content licensed under CC-BY-SA 3.0 to Space Wizards Federation & Contributors.
- You may not use CrystallEdge code in other projects without specific permission from the CrystallEdge author (TheShuEd)
Most assets are licensed under [CC-BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/) unless stated otherwise. Assets have their license and copyright specified in the metadata file. For example, see the [metadata for a crowbar](https://github.com/crystallpunk-14/crystall-punk-14/blob/master/Resources/Textures/Objects/Tools/crowbar.rsi/meta.json).
## Forking CrystallEdge
> [!NOTE]
> Some assets are licensed under the non-commercial [CC-BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/) or similar non-commercial licenses and will need to be removed if you wish to use this project commercially.
You cannot create forks of CrystallEdge to open your own public servers. You can copy a build for educational purposes, code research and contributing to the main build.

View File

@@ -2395,33 +2395,3 @@
id: 8288
time: '2025-10-24T18:17:19.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1837
- author: oldschool_otaku
changes:
- message: Added halloween pumpkins and jack-o'lanterns!
type: Add
id: 8289
time: '2025-10-29T17:15:13.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1822
- author: kin98
changes:
- message: Magical Vision drains Mana now
type: Tweak
id: 8290
time: '2025-10-31T18:11:15.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1832
- author: TheShuEd
changes:
- message: fixed bug with toggling mana vision for entire server
type: Fix
id: 8291
time: '2025-11-01T13:56:03.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1842
- author: Minokaa
changes:
- message: Change emote prefix from @ to %.
type: Tweak
- message: Added custom age to different races.
type: Tweak
id: 8292
time: '2025-11-17T08:38:44.0000000+00:00'
url: https://github.com/crystallpunk-14/crystall-punk-14/pull/1835

View File

@@ -0,0 +1 @@
fishing-paused-map-name = Fish map

View File

@@ -6152,23 +6152,3 @@ ent-CP14WindowFrameWooden = деревянная оконная рама
ent-CP14WindowWoodenBroken = разбитое деревянное окно
.desc = { ent-CP14BaseWindowFrameBroken.desc }
ent-CP14HalloweenPumpkin = страшная тыква
.desc = Когда-то это была обычная тыква... А теперь это страшная тыква!
ent-CP14HalloweenPumpkinEmmisiveBase = тыквенный фонарь
.desc = Ууууу! Страшная!
ent-CP14JackOLanternVariant1 = { ent-CP14HalloweenPumpkinEmmisiveBase }
.desc = { ent-CP14HalloweenPumpkinEmmisiveBase.desc }
ent-CP14JackOLanternVariant2 = { ent-CP14HalloweenPumpkinEmmisiveBase }
.desc = { ent-CP14HalloweenPumpkinEmmisiveBase.desc }
ent-CP14JackOLanternVariant3 = { ent-CP14HalloweenPumpkinEmmisiveBase }
.desc = { ent-CP14HalloweenPumpkinEmmisiveBase.desc }
ent-CP14JackOLanternVariant4 = { ent-CP14HalloweenPumpkinEmmisiveBase }
.desc = { ent-CP14HalloweenPumpkinEmmisiveBase.desc }
ent-CP14JackOLantern = спавнер тыквенного фонаря
.desc = { ent-CP14HalloweenPumpkinEmmisiveBase.desc }

View File

@@ -0,0 +1 @@
fishing-paused-map-name = Рыбная карта

View File

@@ -4,8 +4,8 @@ meta:
engineVersion: 266.0.0
forkId: ""
forkVersion: ""
time: 11/05/2025 15:54:43
entityCount: 5606
time: 09/30/2025 17:24:34
entityCount: 5610
maps:
- 1
grids:
@@ -1432,13 +1432,6 @@ entities:
parent: 1
- proto: CP14Bucket
entities:
- uid: 2134
components:
- type: Transform
parent: 4
- type: Physics
canCollide: False
- type: InsideEntityStorage
- uid: 7155
components:
- type: Transform
@@ -2457,12 +2450,6 @@ entities:
rot: -1.5707963267948966 rad
pos: 16.595049,-36.47414
parent: 1
- uid: 2132
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -13.966419,-3.1013632
parent: 1
- uid: 4469
components:
- type: Transform
@@ -2550,6 +2537,18 @@ entities:
- type: Transform
pos: 33.559635,16.54992
parent: 1
- uid: 7344
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -14.326934,-2.433626
parent: 1
- uid: 7345
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -12.6811,-2.433626
parent: 1
- uid: 7346
components:
- type: Transform
@@ -5044,13 +5043,6 @@ entities:
- type: Transform
pos: 18.484926,19.120111
parent: 1
- uid: 2133
components:
- type: Transform
parent: 4
- type: Physics
canCollide: False
- type: InsideEntityStorage
- proto: CP14OpenSign
entities:
- uid: 1843
@@ -5841,6 +5833,18 @@ entities:
rot: -1.5707963267948966 rad
pos: 3.5,-9.5
parent: 1
- uid: 9144
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -10.5,-2.5
parent: 1
- uid: 9145
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -11.5,-2.5
parent: 1
- uid: 9146
components:
- type: Transform
@@ -5853,6 +5857,12 @@ entities:
rot: -1.5707963267948966 rad
pos: -14.5,-0.5
parent: 1
- uid: 9149
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -13.5,-1.5
parent: 1
- uid: 9150
components:
- type: Transform
@@ -25540,11 +25550,6 @@ entities:
- type: Transform
pos: 5.5,-39.5
parent: 1
- uid: 2131
components:
- type: Transform
pos: -14.5,-3.5
parent: 1
- uid: 11591
components:
- type: Transform
@@ -25555,6 +25560,12 @@ entities:
- type: Transform
pos: 33.5,15.5
parent: 1
- uid: 11598
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -13.5,-2.5
parent: 1
- uid: 11599
components:
- type: Transform
@@ -26194,6 +26205,16 @@ entities:
- type: Transform
pos: -10.5,-4.5
parent: 1
- uid: 11731
components:
- type: Transform
pos: -11.5,-3.5
parent: 1
- uid: 11732
components:
- type: Transform
pos: -10.5,-3.5
parent: 1
- uid: 11733
components:
- type: Transform
@@ -35578,18 +35599,6 @@ entities:
- type: Transform
pos: -14.5,-14.5
parent: 1
- type: ContainerContainer
containers:
entity_storage: !type:Container
showEnts: False
occludes: True
ents:
- 2133
- 2134
paper_label: !type:ContainerSlot
showEnts: False
occludes: True
ent: null
- uid: 834
components:
- type: Transform

View File

@@ -5,20 +5,16 @@
description: You focus on magical flows to track recent events and scan the aura imprints of other living beings.
components:
- type: Action
useDelay: 0.5
useDelay: 5
itemIconStyle: BigAction
checkCanInteract: false
checkConsciousness: true
sound: !type:SoundPathSpecifier
path: /Audio/Magic/rumble.ogg
icon:
sprite: _CP14/Actions/Spells/meta.rsi
state: magic_vision
- type: InstantAction
event: !type:CP14InstantModularEffectEvent
effects:
- !type:CP14SpellToggleStatusEffect
statusEffect: CP14MetaMagicVisionSpellStatusEffect
event: !type:CP14MagicVisionToggleActionEvent
- type: entity
id: CP14ManaVisionPointer
@@ -55,4 +51,4 @@
color: "#42a4f5"
- type: Clickable
- type: Visibility
layer: 16 #magic vision only
layer: 16 #magic vision only

View File

@@ -96,4 +96,6 @@
- type: Tag
tags:
- FootstepSound
- CP14Mosquito
- CP14Mosquito
- type: CP14Fish
fishBehavior: !type:CP14FishDartBehaviour

View File

@@ -1,148 +0,0 @@
- type: entity
parent: CP14FoodPumpkin
id: CP14HalloweenPumpkin
name: scary pumpkin
description: It was a normal pumpkin one day... Now it's a scary pumpkin!
components:
- type: Sprite
sprite: _CP14/Objects/Misc/halloween_pumpkin.rsi
layers:
- state: base1
map: [ "random" ]
- type: RandomSprite
available:
- random:
base1: ""
base2: ""
base3: ""
base4: ""
- type: Clothing
quickEquip: false
sprite: _CP14/Clothing/Head/halloween_pumpkin_helmet.rsi
equippedPrefix: 0
slots:
- HEAD
- type: entity
parent: FoodInjectableBase
id: CP14HalloweenPumpkinEmmisiveBase
name: jack-o lantern
description: Oooh! Scary!
abstract: true
components:
- type: Sprite
sprite: _CP14/Objects/Misc/halloween_pumpkin.rsi
- type: PointLight
radius: 2.1
energy: 0.9
color: "#FEE68E"
castShadows: true
- type: Item
size: Normal
- type: StaticPrice
price: 6
- type: FlavorProfile
flavors:
- pumpkin
- type: SolutionContainerManager
solutions:
food:
maxVol: 30
reagents:
- ReagentId: PumpkinFlesh
Quantity: 10
- ReagentId: Vitamin
Quantity: 2
- type: SliceableFood
count: 5
sliceTime: 2
slice: CP14FoodPumpkinSlice
- type: Tag
tags:
- CP14FarmFood
- CP14Vegetable
- CP14Pumpkin
- type: entity
parent: CP14HalloweenPumpkinEmmisiveBase
id: CP14JackOLanternVariant1
suffix: Variant 1
categories: [ HideSpawnMenu ]
components:
- type: Sprite
layers:
- state: base1
- state: light-base1
shader: unshaded
- state: light-base1
shader: shaded
- type: entity
parent: CP14HalloweenPumpkinEmmisiveBase
id: CP14JackOLanternVariant2
suffix: Variant 2
categories: [ HideSpawnMenu ]
components:
- type: Sprite
layers:
- state: base2
- state: light-base2
shader: unshaded
- state: light-base2
shader: shaded
- type: entity
parent: CP14HalloweenPumpkinEmmisiveBase
id: CP14JackOLanternVariant3
suffix: Variant 3
categories: [ HideSpawnMenu ]
components:
- type: Sprite
layers:
- state: base3
- state: light-base3
shader: unshaded
- state: light-base3
shader: shaded
- type: entity
parent: CP14HalloweenPumpkinEmmisiveBase
id: CP14JackOLanternVariant4
suffix: Variant 4
categories: [ HideSpawnMenu ]
components:
- type: Sprite
layers:
- state: base4
- state: light-base4
shader: unshaded
- state: light-base4
shader: shaded
- type: entity
id: CP14JackOLantern
name: jack-o lantern spawner
description: Oooh! Scary!
parent: MarkerBase
categories: [ ForkFiltered ]
components:
- type: Sprite
layers:
- state: green
- sprite: _CP14/Objects/Misc/halloween_pumpkin.rsi
state: base2
- sprite: _CP14/Objects/Misc/halloween_pumpkin.rsi
state: light-base2
- type: EntityTableSpawner
table: !type:NestedSelector
tableId: CP14JackOLanternTable
- type: entityTable
id: CP14JackOLanternTable
table: !type:GroupSelector
children:
- id: CP14JackOLanternVariant1
- id: CP14JackOLanternVariant2
- id: CP14JackOLanternVariant3
- id: CP14JackOLanternVariant4

View File

@@ -0,0 +1,61 @@
- type: entity
parent: BaseItem
id: CP14FishingRod
name: fishing rod
description: Wooden stick with string attached.
categories: [ ForkFiltered ]
components:
- type: Item
shape:
- 0,0,0,1
- type: Sprite
sprite: _CP14/Objects/Tools/fishing_rod.rsi
state: icon
- type: Damageable
damageContainer: Inorganic
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 50
behaviors:
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:CP14ModularDisassembleBehavior
- !type:DoActsBehavior
acts: ["Destruction"]
- type: MeleeWeapon
angle: 45
attackRate: 1
wideAnimationRotation: 135
wideAnimation: CP14WeaponArcSlash
damage:
types:
Blunt: 0.1
soundHit:
collection: MetalThud
cPAnimationLength: 0.25
- type: Clothing
equipDelay: 0.25
unequipDelay: 0.25
quickEquip: false
breakOnMove: false
slots:
- neck
- type: CP14FishingRod
- type: UserInterface
interfaces:
enum.CP14FishingUiKey.Key:
type: CP14FishingBoundUserInterface
- type: entity
parent: BaseItem
id: CP14DefaultFishingFloat
name: Fishing float
description: Little floating ball.
categories: [ HideSpawnMenu ]
components:
- type: Sprite
sprite: _CP14/Objects/Tools/float.rsi
state: float

View File

@@ -1,18 +0,0 @@
- type: entity
id: CP14MagicVisionStatusEffect
parent: MobStatusEffectBase
name: Magical vision
components:
- type: StatusEffect
- type: CP14MagicVisionStatusEffect
- type: entity
id: CP14MetaMagicVisionSpellStatusEffect
parent: CP14MagicVisionStatusEffect
name: Magical vision spell
components:
- type: CP14EntityEffectsStatusEffect
effects:
- !type:CP14ManaChange
manaDelta: -5
safe: false

View File

@@ -71,6 +71,8 @@
- type: TileEntityEffect
effects:
- !type:ExtinguishReaction
- type: CP14FishingPond
lootTable: CP14WaterFishingLootTable
- type: entity
parent: CP14FloorWaterOptimized

View File

@@ -0,0 +1,5 @@
- type: entityTable
id: CP14WaterFishingLootTable
table: !type:GroupSelector
children:
- id: CP14MobMonsterFlem

View File

@@ -0,0 +1,19 @@
- type: CP14FishingMinigameStyle
id: Default
background:
texture: /Textures/_CP14/Interface/Fishing/Default/background.png
size: 78, 298
offset: 0, 0
fishIcon:
texture: /Textures/_CP14/Interface/Fishing/Default/fish_icon.png
size: 22, 18
offset: 26, 12
progressbar:
texture: /Textures/_CP14/Interface/Fishing/Default/progressbar.png
size: 4, 284
offset: 6, 8
float:
texture: /Textures/_CP14/Interface/Fishing/Default/float.png
size: 22, 76
offset: 26, 12
fishingMinigameSize: 281

View File

@@ -39,13 +39,3 @@
protoId: CP14FoodDoughMedium
count: 1
result: CP14FoodDoughMediumFlat
- type: CP14Recipe
id: CP14HalloweenPumpkin
tag: CP14RecipeCooking
craftTime: 1
requirements:
- !type:ProtoIdResource
protoId: CP14FoodPumpkin
count: 1
result: CP14HalloweenPumpkin

View File

@@ -250,17 +250,4 @@
- !type:StackResource
stack: CP14Cloth
count: 2
result: CP14Rope
- type: CP14Recipe
id: CP14JackOLantern
tag: CP14RecipeWorkbench
craftTime: 2
requirements:
- !type:ProtoIdResource
protoId: CP14HalloweenPumpkin
count: 1
- !type:ProtoIdResource
protoId: CP14Candle
count: 1
result: CP14JackOLanternVariant2
result: CP14Rope

View File

@@ -11,10 +11,6 @@
maleFirstNames: CP14_Names_Carcat_First
femaleFirstNames: CP14_Names_Carcat_First
naming: First
minAge: 18
maxAge: 110
youngAge: 20
oldAge: 80
- type: speciesBaseSprites
id: CP14MobCarcatSprites

View File

@@ -10,10 +10,6 @@
maleFirstNames: CP14_Names_Dwarf_Male_First #TODO
femaleFirstNames: CP14_Names_Dwarf_Female_First #TODO
lastNames: CP14_Names_Dwarf_Last #TODO
minAge: 18
maxAge: 350
youngAge: 100
oldAge: 175
- type: speciesBaseSprites
id: CP14MobDwarfSprites

View File

@@ -10,10 +10,6 @@
maleFirstNames: CP14_Names_Elf_Male_First
femaleFirstNames: CP14_Names_Elf_Female_First
lastNames: CP14_Names_Elf_Last
minAge: 18
maxAge: 900
youngAge: 100
oldAge: 700
- type: speciesBaseSprites
id: CP14MobElfSprites

View File

@@ -11,10 +11,6 @@
maleFirstNames: CP14_Names_Goblin_Male_First
femaleFirstNames: CP14_Names_Goblin_Female_First
naming: First
minAge: 18
maxAge: 70
youngAge: 25
oldAge: 55
- type: speciesBaseSprites
id: CP14MobGoblinSprites

View File

@@ -11,10 +11,6 @@
maleFirstNames: CP14_Names_Silva_Male_First
femaleFirstNames: CP14_Names_Silva_Female_First
naming: First
minAge: 18
maxAge: 500
youngAge: 100
oldAge: 300
- type: speciesBaseSprites
id: CP14MobSilvaSprites

View File

@@ -10,10 +10,6 @@
maleFirstNames: CP14_Names_Tiefling_Male_First
femaleFirstNames: CP14_Names_Tiefling_Female_First
lastNames: CP14_Names_Tiefling_Last
minAge: 18
maxAge: 120
youngAge: 50
oldAge: 80
# The lack of a layer means that
# this person cannot have round-start anything

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd. Shadow step and Shadow grab created by .kreks. Shadow swap created by TornadoTech.",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd, electric_trap by nimfar11",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by .kreks., tiefling_revenge, fire_music, firewave by TheShuEd, fire_trap by nimfar11",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd, cure_wounds created by .kreks.",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by .kreks., signal_light_blue, signal_light_red, signal_light_yellow by TheShuEd",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd, vulnerability by Sable",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Nimfar11",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd, ice_dagger by .kreks., ice_trap by nimfar11",
"states": [
{

View File

@@ -4,7 +4,7 @@
"x": 32,
"y": 32
},
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by TheShuEd",
"states": [
{

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand)",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand)",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand)",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand) & resprite omsoyk",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand)",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand)",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand) & resprite omsoyk",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand) & resprite omsoyk",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand) & resprite omsoyk",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand) & resprite omsoyk",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Ell_Good (icon) and PhantomRU (equiped, recolor, inhand) & resprite omsoyk",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Jaraten",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Jaraten",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Lucson1337",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy, recolored by Dinazewwr",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Jaraten",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Jaraten",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Lucson1337",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by Jaraten (discord/GitHub)",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by KBAS5",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "CC-BY-SA-4.0",
"license": "All right reserved",
"copyright": "Created by creamy",
"size": {
"x": 48,

Some files were not shown because too many files have changed in this diff Show More