Compare commits

..

12 Commits

Author SHA1 Message Date
Ed
5b6108377e relicense assets 2026-02-20 23:38:12 +03:00
Ed
95b4b05574 MIT license 2026-02-19 14:09:33 +03:00
CrystallEdge Server
9152f270a5 Automatic changelog update 2025-11-17 11:39:50 +03:00
Minokaa
1606ff154d change emote prefix and added custom age to different races (#1835)
* change emote prefix from @ to % and added age to different races

* alt emotes prefix

* fix formating

* correcting ages
2025-11-17 11:38:44 +03:00
github-actions[bot]
0ecbc0ac35 @mojokelp has signed the CLA in crystallpunk-14/crystall-punk-14#1847 2025-11-09 04:41:44 +00:00
Viator-MV
bbbaa9cbfa map-fixes-25.11.05 (#1845) 2025-11-05 20:10:05 +03:00
CrystallEdge Server
ccf58f664c Automatic changelog update 2025-11-01 16:57:09 +03:00
Red
33a02ffcef Update CP14ClientMagicVisionSystem.cs (#1842) 2025-11-01 16:56:03 +03:00
CrystallEdge Server
ade45ee8e3 Automatic changelog update 2025-10-31 21:12:21 +03:00
kin98
0fdc56c796 Make magical vision drain Mana (#1832)
* added generic Entity Effects status effect component

* added Magic Vision Statuseffect component

* renamed visionmask to Visibilitymask and added StatusEffectComponent notice comment

* added two event listeners on MagicVisonStatusEffect applied and removed

* moved changes to server side

* moved Component serverside

* removed Overlay Property

* Added magic vison status effect prototype and applying

* cleaned upnew lines

* added new prototype

* moved Magic vision status effect component to shared again

* fixed applying mask

* cleaned new lines

* Moved to components folder

* marked MagicVisionComponent obsolete and changed protoid name

* Added parent MobStatusEffectBase

* added mana cost to Magical vision spell

* removed unneeded constructor

* Added the system

* added statuseffect eventlistners for applied and removed also removed old event listners

* removed old magic vision component check

* Removed Data field attribute

* added back Data field attribute

* added access atribute

* moved Status effect update to server

* removed shared System moved all to server side

* Update Content.Shared/_CP14/StatusEffect/Components/CP14EntityEffectsStatusEffectComponent.cs

Co-authored-by: Red <96445749+TheShuEd@users.noreply.github.com>

* Fix typo in DataField attribute for Effects list

* Obliterated CP14MagicVisionComponent from existence

* Fix comment capitalization in CP14EntityEffectsStatusEffectComponent

* Fix summary capitalization in CP14EntityEffectsStatusEffectComponent

* Refactor CP14MagicVisionSystem.cs by removing blank lines

Removed unnecessary blank lines for cleaner code.

* Remove status effect event handlers

Removed event subscription and related methods for status effects.

* Remove empty line in OnExamined method

* Added a Spell toggle status effect

* fixed datfields shouldnt be static

* imlpemented status applying in yml

* cleaned white space :3

* changed toggle to has status effect

* fix leftover

* added check for firsttime predict so it doesnt get applied twice

* added getvismaskevent to statuseffect relay

* changed event lisnter to use CP14MagicVisionStatusEffectComponent to prevent future conflicts

* removed unneeded _status property

* added check for if its the last status effect on remove

* added check if Status effect is already present if applied

* changed check to component instead of entity

* changed ent target to player.localEntity

* fix: removed has effect check as it already has the effect when first apllied

* changed event to on player attached

* removed first time predicted check

* changed cooldown to 0.5 seconds

* made Spell mana change effect not save

* added status efect applied event listner back and moved apply and remove overlay to separete methods

* removed replaced action event

* added fix to let nextupdate catch up to CurTime

* fix: status effect not beeing removed when crit or dead

* fix: Action beeing able to be used while dead

* fix: added prediction check to applied back for double apply and remove bug

---------

Co-authored-by: Red <96445749+TheShuEd@users.noreply.github.com>
2025-10-31 21:11:15 +03:00
CrystallEdge Server
ecd5bf3019 Automatic changelog update 2025-10-29 20:16:18 +03:00
nukkuminen
b6f31ad49f Happy spooky month! (#1822)
* todo finish tomorrow

* fixing random sprite error, minor rewrite

* translation

* fuck comments

* pumpkin is real

* adjust price for jack-o'lantern
2025-10-29 20:15:13 +03:00
326 changed files with 845 additions and 1535 deletions

View File

@@ -1,38 +0,0 @@
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,7 +318,6 @@ 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,6 +83,10 @@ 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

@@ -1,86 +0,0 @@
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

@@ -1,40 +0,0 @@
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

@@ -1,7 +0,0 @@
<!-- 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

@@ -1,85 +0,0 @@
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,7 +11,6 @@ namespace Content.Client._CP14.Input
human.AddFunction(CP14ContentKeyFunctions.OpenBelt2);
human.AddFunction(CP14ContentKeyFunctions.SmartEquipBelt2);
human.AddFunction(CP14ContentKeyFunctions.CP14OpenSkillMenu);
human.AddFunction(CP14ContentKeyFunctions.CP14FishingAction);
}
}
}

View File

@@ -1,6 +1,7 @@
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;
@@ -21,14 +22,16 @@ 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 SoundSpecifier _startSound = new SoundPathSpecifier(new ResPath("/Audio/Effects/eye_open.ogg"));
private SoundSpecifier _endSound = new SoundPathSpecifier(new ResPath("/Audio/Effects/eye_close.ogg"));
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"));
public override void Initialize()
{
@@ -36,71 +39,52 @@ public sealed class CP14ClientMagicVisionSystem : CP14SharedMagicVisionSystem
SubscribeLocalEvent<CP14MagicVisionMarkerComponent, AfterAutoHandleStateEvent>(OnHandleStateMarker);
SubscribeLocalEvent<CP14MagicVisionComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<CP14MagicVisionComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerAttachedEvent>>(OnPlayerAttached);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerDetachedEvent>>(OnPlayerDetached);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectAppliedEvent>(OnStatusEffectApplied);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRemovedEvent>(OnStatusEffectRemoved);
SubscribeLocalEvent<CP14MagicVisionComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<CP14MagicVisionComponent, ComponentShutdown>(OnComponentShutdown);
}
private void OnComponentShutdown(Entity<CP14MagicVisionComponent> ent, ref ComponentShutdown args)
private void OnPlayerAttached(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
{
if (_player.LocalEntity != ent)
return;
if (_overlay != null)
{
_overlayMan.RemoveOverlay(_overlay);
_overlay = null;
}
if (_overlay2 != null)
{
_overlayMan.RemoveOverlay(_overlay2);
_overlay2 = null;
}
_audio.PlayGlobal(_endSound, ent);
}
private void OnComponentInit(Entity<CP14MagicVisionComponent> ent, ref ComponentInit args)
{
if (_player.LocalEntity != ent)
if (args.Args.Entity != _player.LocalEntity)
return;
_overlay = new CP14MagicVisionOverlay();
_overlayMan.AddOverlay(_overlay);
_overlay.StartOverlay = _timing.CurTime;
_overlay2 = new CP14MagicVisionNoirOverlay();
_overlayMan.AddOverlay(_overlay2);
_audio.PlayGlobal(_startSound, ent);
ApplyOverlay(ent);
}
private void OnPlayerAttached(Entity<CP14MagicVisionComponent> ent, ref LocalPlayerAttachedEvent args)
private void OnStatusEffectApplied(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
{
_overlay = new CP14MagicVisionOverlay();
_overlayMan.AddOverlay(_overlay);
_overlay.StartOverlay = _timing.CurTime;
if (args.Target != _player.LocalEntity)
return;
_overlay2 = new CP14MagicVisionNoirOverlay();
_overlayMan.AddOverlay(_overlay2);
//Prevents it from being applied twice
if (_timing.IsFirstTimePredicted)
return;
_audio.PlayGlobal(_startSound, ent);
ApplyOverlay(ent);
}
private void OnPlayerDetached(Entity<CP14MagicVisionComponent> ent, ref LocalPlayerDetachedEvent args)
private void OnPlayerDetached(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
{
if (_overlay != null)
{
_overlayMan.RemoveOverlay(_overlay);
_overlay = null;
}
if (_overlay2 != null)
{
_overlayMan.RemoveOverlay(_overlay2);
_overlay2 = null;
}
_audio.PlayGlobal(_endSound, ent);
if (args.Args.Entity != _player.LocalEntity)
return;
RemoveOverlay(ent);
}
private void OnStatusEffectRemoved(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
{
if (args.Target != _player.LocalEntity)
return;
//Prevents it from beeing removed twice
if (_timing.IsFirstTimePredicted)
return;
RemoveOverlay(ent);
}
protected override void OnExamined(Entity<CP14MagicVisionMarkerComponent> ent, ref ExaminedEvent args)
@@ -154,6 +138,38 @@ 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, Color.White.WithAlpha((float)alpha));
_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);
}
}

View File

@@ -44,9 +44,6 @@ 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

@@ -1,122 +0,0 @@
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,26 +13,19 @@ public sealed class CP14MagicVisionSystem : CP14SharedMagicVisionSystem
{
base.Initialize();
SubscribeLocalEvent<MetaDataComponent, CP14MagicVisionToggleActionEvent>(OnMagicVisionToggle);
SubscribeLocalEvent<CP14MagicVisionComponent, GetVisMaskEvent>(OnGetVisMask);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRelayedEvent<GetVisMaskEvent>>(OnGetVisMask);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectAppliedEvent>(OnApplied);
SubscribeLocalEvent<CP14MagicVisionStatusEffectComponent, StatusEffectRemovedEvent>(OnRemoved);
}
private void OnGetVisMask(Entity<CP14MagicVisionComponent> ent, ref GetVisMaskEvent args)
private void OnGetVisMask(Entity<CP14MagicVisionStatusEffectComponent> ent, ref StatusEffectRelayedEvent<GetVisMaskEvent> args)
{
args.VisibilityMask |= (int)VisibilityFlags.CP14MagicVision;
}
var appliedMask = (int)CP14MagicVisionStatusEffectComponent.VisibilityMask;
var newArgs = args.Args;
private void OnMagicVisionToggle(Entity<MetaDataComponent> ent, ref CP14MagicVisionToggleActionEvent args)
{
if (!HasComp<CP14MagicVisionComponent>(ent))
{
AddComp<CP14MagicVisionComponent>(ent);
}
else
{
RemComp<CP14MagicVisionComponent>(ent);
}
_eye.RefreshVisibilityMask(ent.Owner);
newArgs.VisibilityMask |= appliedMask;
args = args with { Args = newArgs };
}
public override void Update(float frameTime)
@@ -51,4 +44,14 @@ 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

@@ -0,0 +1,38 @@
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

@@ -0,0 +1,29 @@
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,6 +24,10 @@ 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,6 +7,7 @@ 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;
@@ -16,6 +17,8 @@ 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

@@ -1,46 +0,0 @@
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

@@ -1,11 +0,0 @@
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

@@ -1,64 +0,0 @@
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

@@ -1,21 +0,0 @@
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

@@ -1,278 +0,0 @@
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

@@ -1,53 +0,0 @@
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

@@ -1,18 +0,0 @@
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

@@ -1,105 +0,0 @@
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,6 +9,5 @@ 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

@@ -0,0 +1,24 @@
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,6 +4,7 @@ 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;
@@ -27,6 +28,15 @@ 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)
@@ -148,7 +158,3 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem
Dirty(ent, markerComp);
}
}
public sealed partial class CP14MagicVisionToggleActionEvent : InstantActionEvent
{
}

View File

@@ -1,11 +0,0 @@
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

@@ -0,0 +1,17 @@
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;
}

View File

@@ -1,15 +0,0 @@
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,10 +5,6 @@ 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.
@@ -17,13 +13,11 @@ We welcome any support from the community in the development of the game! Join o
[More detailed instructions on building the project.](https://docs.spacestation14.com/en/general-development/setup.html)
## Licensing/Attriibution
## License
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)
All code for the content repository is licensed under the [MIT license](https://github.com/crystallpunk-14/crystall-punk-14/blob/master/LICENSE.TXT).
## Forking CrystallEdge
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).
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.
> [!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.

View File

@@ -2395,3 +2395,33 @@
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

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

View File

@@ -6152,3 +6152,23 @@ 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

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

View File

@@ -4,8 +4,8 @@ meta:
engineVersion: 266.0.0
forkId: ""
forkVersion: ""
time: 09/30/2025 17:24:34
entityCount: 5610
time: 11/05/2025 15:54:43
entityCount: 5606
maps:
- 1
grids:
@@ -1432,6 +1432,13 @@ entities:
parent: 1
- proto: CP14Bucket
entities:
- uid: 2134
components:
- type: Transform
parent: 4
- type: Physics
canCollide: False
- type: InsideEntityStorage
- uid: 7155
components:
- type: Transform
@@ -2450,6 +2457,12 @@ 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
@@ -2537,18 +2550,6 @@ 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
@@ -5043,6 +5044,13 @@ 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
@@ -5833,18 +5841,6 @@ 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
@@ -5857,12 +5853,6 @@ 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
@@ -25550,6 +25540,11 @@ 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
@@ -25560,12 +25555,6 @@ 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
@@ -26205,16 +26194,6 @@ 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
@@ -35599,6 +35578,18 @@ 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,16 +5,20 @@
description: You focus on magical flows to track recent events and scan the aura imprints of other living beings.
components:
- type: Action
useDelay: 5
useDelay: 0.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:CP14MagicVisionToggleActionEvent
event: !type:CP14InstantModularEffectEvent
effects:
- !type:CP14SpellToggleStatusEffect
statusEffect: CP14MetaMagicVisionSpellStatusEffect
- type: entity
id: CP14ManaVisionPointer
@@ -51,4 +55,4 @@
color: "#42a4f5"
- type: Clickable
- type: Visibility
layer: 16 #magic vision only
layer: 16 #magic vision only

View File

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

View File

@@ -0,0 +1,148 @@
- 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

@@ -1,61 +0,0 @@
- 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

@@ -0,0 +1,18 @@
- 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,8 +71,6 @@
- type: TileEntityEffect
effects:
- !type:ExtinguishReaction
- type: CP14FishingPond
lootTable: CP14WaterFishingLootTable
- type: entity
parent: CP14FloorWaterOptimized

View File

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

View File

@@ -1,19 +0,0 @@
- 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,3 +39,13 @@
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,4 +250,17 @@
- !type:StackResource
stack: CP14Cloth
count: 2
result: CP14Rope
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

View File

@@ -11,6 +11,10 @@
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,6 +10,10 @@
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,6 +10,10 @@
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,6 +11,10 @@
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,6 +11,10 @@
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,6 +10,10 @@
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": "All right reserved",
"license": "CC-BY-SA-4.0",
"copyright": "Created by TheShuEd",
"states": [
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
{
"version": 1,
"license": "All right reserved",
"license": "CC-BY-SA-4.0",
"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": "All right reserved",
"license": "CC-BY-SA-4.0",
"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": "All right reserved",
"license": "CC-BY-SA-4.0",
"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": "All right reserved",
"license": "CC-BY-SA-4.0",
"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": "All right reserved",
"license": "CC-BY-SA-4.0",
"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": "All right reserved",
"license": "CC-BY-SA-4.0",
"copyright": "Created by creamy",
"size": {
"x": 32,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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