Compare commits

...

15 Commits

Author SHA1 Message Date
Deserty0
6575aa19c4 Revert "Try to predict"
This reverts commit 48a5620099.
2025-09-04 02:35:12 +10:00
Deserty0
7ac03a54e4 fix 2025-09-04 01:47:14 +10:00
Deserty0
874c524538 Update Program.OpenGL.cs 2025-09-04 01:18:13 +10:00
Deserty0
8623324fab 123 2025-09-04 01:10:03 +10:00
Ed
80e429c8fa Merge branch 'master' into fishing 2025-04-11 19:53:22 +03:00
Ed
d96a4b6638 Merge branch 'master' into fishing 2025-04-09 16:49:07 +03:00
Tornado Tech
48a5620099 Try to predict 2025-01-17 16:22:37 +10:00
Tornado Tech
ad70108cdf Separated rods to parts 2024-12-17 21:34:39 +10:00
Tornado Tech
97d08097fe Fix again 2024-12-15 02:21:40 +10:00
Tornado Tech
961f365f52 Fix 2024-12-15 01:16:29 +10:00
Tornado Tech
78c711950a FUUUUCK 2024-12-15 00:40:43 +10:00
Tornado Tech
c0221b1445 Finaly sprites 2024-12-14 17:18:39 +10:00
Tornado Tech
dbcf17bab2 Updated system 2024-12-09 02:29:33 +10:00
Tornado Tech
a88e0ee00f Updated fishing process 2024-12-03 01:17:00 +10:00
Tornado Tech
ba60bc7176 Fishing init without sprites 2024-12-01 04:28:25 +10:00
46 changed files with 1179 additions and 1 deletions

View File

@@ -0,0 +1,149 @@
using System.Numerics;
using Content.Client.Resources;
using Content.Shared._CP14.Fishing.Components;
using Content.Shared._CP14.Fishing.Prototypes;
using Content.Shared._CP14.Fishing.Systems;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
namespace Content.Client._CP14.Fishing;
public sealed class CP14FishingOverlay : Overlay
{
[Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly IEntityManager _entity = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
private readonly SpriteSystem _sprite;
private readonly TransformSystem _transform;
private readonly CP14SharedFishingProcessSystem _sharedFishingProcess;
private Texture _backgroundTexture = default!;
private Texture _handleTopTexture = default!;
private Texture _handleMiddleTexture = default!;
private Texture _handleBottomTexture = default!;
private Texture _lootTexture = default!;
private Vector2 _backgroundOffset;
private Vector2 _backgroundHandleOffset;
private Vector2 _backgroundHandleSize;
private Vector2 _progressOffset;
private Vector2 _progressSize;
private EntityUid _process = EntityUid.Invalid;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public CP14FishingOverlay()
{
IoCManager.InjectDependencies(this);
_sprite = _entity.System<SpriteSystem>();
_transform = _entity.System<TransformSystem>();
_sharedFishingProcess = _entity.System<CP14SharedFishingProcessSystem>();
}
protected override void Draw(in OverlayDrawArgs args)
{
if (_player.LocalEntity is not { } localEntity)
return;
if (!_sharedFishingProcess.TryGetByUser(localEntity, out var fishingProcess))
return;
// Refresh the texture cache, with a new fishing process
if (_process != fishingProcess.Value.Owner)
{
_process = fishingProcess.Value.Owner;
UpdateCachedStyleSheet(_sharedFishingProcess.GetStyle(fishingProcess.Value));
var prototype = _prototype.Index(fishingProcess.Value.Comp.LootProtoId);
var iconPath = CP14FishingIconComponent.DefaultTexturePath;
if (prototype.Components.TryGetComponent(_factory.GetComponentName(typeof(CP14FishingIconComponent)), out var iconComponent))
{
var comp = (CP14FishingIconComponent) iconComponent;
iconPath = comp.TexturePath;
}
_lootTexture = _resourceCache.GetTexture(iconPath);
}
// Getting the position of the player we will be working from
var worldPosition = _transform.GetWorldPosition(localEntity);
// Calculate the shift of the player relative to the bottom of the coordinates
var playerOffset = fishingProcess.Value.Comp.PlayerPositionNormalized * _backgroundHandleSize;
var playerHalfSize = fishingProcess.Value.Comp.PlayerHalfSizeNormalized * _backgroundHandleSize;
var lootOffset = fishingProcess.Value.Comp.LootPositionNormalized * _backgroundHandleSize + Vector2.UnitX * _backgroundHandleSize.X / 2;
DrawBackground(args.WorldHandle, worldPosition - _backgroundOffset);
DrawProgress(args.WorldHandle, worldPosition - _backgroundOffset + _progressOffset, _progressSize, fishingProcess.Value.Comp.Progress);
DrawHandle(args.WorldHandle, worldPosition - _backgroundOffset + _backgroundHandleOffset + playerOffset, playerHalfSize);
DrawLoot(args.WorldHandle, worldPosition - _backgroundOffset + _backgroundHandleOffset + lootOffset);
}
private void DrawBackground(DrawingHandleWorld handle, Vector2 position)
{
handle.DrawTexture(_backgroundTexture, position);
}
private void DrawProgress(DrawingHandleWorld handle, Vector2 position, Vector2 size, float progress)
{
var vectorA = position;
var vectorB = position + new Vector2(size.X, size.Y * progress);
var box = new Box2(vectorA, vectorB);
handle.DrawRect(box, Color.Aqua);
}
private void DrawHandle(DrawingHandleWorld handle, Vector2 position, Vector2 halfSize)
{
var cursor = position - halfSize;
// Bottom
handle.DrawTexture(_handleBottomTexture, cursor);
cursor += new Vector2(0, _handleBottomTexture.Height / 32f);
// Middle
while (cursor.Y < position.Y + halfSize.Y - _handleTopTexture.Height / 32f)
{
handle.DrawTexture(_handleMiddleTexture, cursor);
cursor += new Vector2(0, _handleMiddleTexture.Height / 32f);
}
// Front
handle.DrawTexture(_handleTopTexture, cursor);
}
private void DrawLoot(DrawingHandleWorld handle, Vector2 position)
{
handle.DrawTexture(_lootTexture, position - _lootTexture.Size / 64f);
}
private void UpdateCachedStyleSheet(CP14FishingProcessStyleSheetPrototype styleSheet)
{
_backgroundTexture = _resourceCache.GetTexture(styleSheet.Background.Texture);
_handleTopTexture = _resourceCache.GetTexture(styleSheet.Handle.TopTexture);
_handleMiddleTexture = _resourceCache.GetTexture(styleSheet.Handle.MiddleTexture);
_handleBottomTexture = _resourceCache.GetTexture(styleSheet.Handle.BottomTexture);
_backgroundOffset = styleSheet.Background.Offset + Vector2.UnitX * _backgroundTexture.Width / 32f;
_backgroundHandleOffset = styleSheet.Background.HandleOffset;
_backgroundHandleSize = styleSheet.Background.HandleSize;
_progressOffset = styleSheet.Background.ProgressOffset;
_progressSize = styleSheet.Background.ProgressSize;
}
}

View File

@@ -0,0 +1,23 @@
using Content.Client.Overlays;
using Robust.Client.Graphics;
namespace Content.Client._CP14.Fishing;
public sealed class CP14FishingOverlaySystem : EntitySystem
{
[Dependency] private readonly IOverlayManager _overlay = default!;
public override void Initialize()
{
base.Initialize();
_overlay.AddOverlay(new CP14FishingOverlay());
}
public override void Shutdown()
{
base.Shutdown();
_overlay.RemoveOverlay<StencilOverlay>();
}
}

View File

@@ -0,0 +1,5 @@
using Content.Shared._CP14.Fishing.Systems;
namespace Content.Client._CP14.Fishing;
public sealed class CP14FishingProcessSystem : CP14SharedFishingProcessSystem;

View File

@@ -0,0 +1,35 @@
using Content.Client.Hands.Systems;
using Content.Shared._CP14.Fishing.Components;
using Content.Shared._CP14.Fishing.Systems;
using Robust.Client.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Timing;
namespace Content.Client._CP14.Fishing;
public sealed class CP14FishingRodSystem : CP14SharedFishingRodSystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly InputSystem _input = default!;
[Dependency] private readonly HandsSystem _hands = default!;
public override void Update(float frameTime)
{
base.Update(frameTime);
if (!_timing.IsFirstTimePredicted)
return;
var handUid = _hands.GetActiveHandEntity();
if (!TryComp<CP14FishingRodComponent>(handUid, out var fishingRodComponent))
return;
var reelKey = _input.CmdStates.GetState(EngineKeyFunctions.UseSecondary) == BoundKeyState.Down;
if (fishingRodComponent.Reeling == reelKey)
return;
RaisePredictiveEvent(new RequestFishingRodReelMessage(reelKey));
}
}

View File

@@ -0,0 +1,121 @@
using Content.Shared._CP14.Fishing.Components;
using Content.Shared._CP14.Fishing.Core;
using Content.Shared._CP14.Fishing.Core.Behaviors;
using Content.Shared._CP14.Fishing.Events;
using Content.Shared._CP14.Fishing.Systems;
using Content.Shared.Throwing;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._CP14.Fishing;
public sealed class CP14FishingProcessSystem : CP14SharedFishingProcessSystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;
[Dependency] private readonly CP14FishingPoolSystem _pool = default!;
/*
private readonly TimeSpan _dirtyDelay = TimeSpan.FromTicks(10000000000000);
private TimeSpan _dirtyDelayTime;
*/
public override void Update(float frameTime)
{
// DON'T CALL BASE METHOD!!!
var query = EntityQueryEnumerator<CP14FishingProcessComponent>();
while (query.MoveNext(out var entityUid, out var processComponent))
{
Update((entityUid, processComponent), frameTime * 2);
}
}
public override void FishPreUpdate(Entity<CP14FishingProcessComponent> process, Fish fish, float frameTime)
{
base.FishPreUpdate(process, fish, frameTime);
fish.UpdateSpeed(_random, _timing);
Dirty(process);
}
public override void UpdateDirty(Entity<CP14FishingProcessComponent> process)
{
base.UpdateDirty(process);
/*
if (_timing.CurTime < _dirtyDelayTime)
return;
_dirtyDelayTime = _timing.CurTime + _dirtyDelay;
Dirty(process);
*/
}
public override void Finish(Entity<CP14FishingProcessComponent> process, bool success)
{
base.Finish(process, success);
if (success)
{
Reward(process);
}
// Raising events before deletion
var ev = new CP14FishingFinishedEvent(success);
RaiseLocalEvent(process, ref ev, true);
// Either way, we need to delete the process
Stop(process);
}
public override void Reward(Entity<CP14FishingProcessComponent> process)
{
base.Reward(process);
var pool = GetPool(process);
var rod = GetRod(process);
var coordinates = Transform(pool).Coordinates;
var targetCoordinates = Transform(process.Comp.User!.Value).Coordinates;
var loot = Spawn(process.Comp.LootProtoId, coordinates);
_throwing.TryThrow(loot, targetCoordinates, rod.Comp.ThrowPower);
}
public Entity<CP14FishingProcessComponent> Start(
Entity<CP14FishingRodComponent> fishingRod,
Entity<CP14FishingPoolComponent> fishingPool,
EntityUid user)
{
var process = CreateProcess(fishingRod.Owner);
var loot = _pool.GetLootPrototypeId(fishingPool);
var style = GetStyle(fishingRod);
// Save entities
process.Comp.FishingRod = fishingRod;
process.Comp.FishingPool = fishingPool;
process.Comp.User = user;
process.Comp.Player = new Player(fishingRod.Comp.Size);
process.Comp.Fish = new Fish(new MixedBehavior(), _timing.CurTime + TimeSpan.FromSeconds(0.5f));
process.Comp.LootProtoId = loot;
process.Comp.StyleSheet = style;
Dirty(process);
Log.Debug($"Started new fishing process at {process}");
return process;
}
public Entity<CP14FishingProcessComponent> CreateProcess(EntityUid parent)
{
var entityUid = SpawnAttachedTo(null, Transform(parent).Coordinates);
var ensureComponent = AddComp<CP14FishingProcessComponent>(entityUid);
return (entityUid, ensureComponent);
}
}

View File

@@ -0,0 +1,31 @@
using Content.Shared._CP14.Fishing.Components;
using Content.Shared._CP14.Fishing.Systems;
using Content.Shared.Interaction;
namespace Content.Server._CP14.Fishing;
public sealed class CP14FishingRodSystem : CP14SharedFishingRodSystem
{
[Dependency] private readonly CP14FishingProcessSystem _fishingProcess = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14FishingPoolComponent, AfterInteractUsingEvent>(OnAfterInteractUsing);
}
private void OnAfterInteractUsing(Entity<CP14FishingPoolComponent> entity, ref AfterInteractUsingEvent args)
{
if (args.Handled || !args.CanReach)
return;
if (!TryComp<CP14FishingRodComponent>(args.Used, out var fishingRodComponent))
return;
if (fishingRodComponent.Process is not null)
return;
fishingRodComponent.Process = _fishingProcess.Start((args.Used, fishingRodComponent), entity, args.User);
}
}

View File

@@ -0,0 +1,13 @@
using Robust.Shared.GameStates;
using Robust.Shared.Utility;
namespace Content.Shared._CP14.Fishing.Components;
[RegisterComponent, NetworkedComponent]
public sealed partial class CP14FishingIconComponent : Component
{
public static readonly ResPath DefaultTexturePath = new("/Textures/_CP14/Interface/Fishing/Icons/default.png");
[DataField]
public ResPath TexturePath = DefaultTexturePath;
}

View File

@@ -0,0 +1,12 @@
using Content.Shared._CP14.Fishing.Prototypes;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Fishing.Components;
[RegisterComponent, NetworkedComponent]
public sealed partial class CP14FishingPoolComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public ProtoId<CP14FishingPoolLootTablePrototype> LootTable = "Default";
}

View File

@@ -0,0 +1,65 @@
using System.Numerics;
using Content.Shared._CP14.Fishing.Core;
using Content.Shared._CP14.Fishing.Prototypes;
using Content.Shared._CP14.Fishing.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Fishing.Components;
[Access(typeof(CP14SharedFishingProcessSystem))]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class CP14FishingProcessComponent : Component
{
/**
* Boxes
*/
[ViewVariables, AutoNetworkedField]
public Player? Player;
[ViewVariables, AutoNetworkedField]
public Fish? Fish;
/**
* Progress
*/
[ViewVariables, AutoNetworkedField]
public float Progress;
/**
* Saved entities
*/
[ViewVariables, AutoNetworkedField]
public EntityUid? FishingRod = null;
[ViewVariables, AutoNetworkedField]
public EntityUid? User = null;
[ViewVariables, AutoNetworkedField]
public EntityUid? FishingPool = null;
/**
* Loot
*/
[ViewVariables, AutoNetworkedField]
public EntProtoId LootProtoId;
/**
* Style
*/
[ViewVariables]
public CP14FishingProcessStyleSheetPrototype? StyleSheet;
/**
* Normalized
*/
public Vector2 LootPositionNormalized => Vector2.UnitY * Fish?.Position ?? Vector2.Zero;
public Vector2 PlayerPositionNormalized => Vector2.UnitY * Player?.Position ?? Vector2.Zero;
public Vector2 PlayerHalfSizeNormalized => Vector2.UnitY * Player?.HalfSize ?? Vector2.Zero;
}

View File

@@ -0,0 +1,45 @@
using Content.Shared._CP14.Fishing.Prototypes;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Fishing.Components;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class CP14FishingRodComponent : Component
{
[ViewVariables]
public static readonly ProtoId<CP14FishingProcessStyleSheetPrototype> DefaultStyle = "Default";
[ViewVariables]
public EntityUid? Process;
[ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public bool Reeling;
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float Speed = 0.1f;
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float Gravity = 0.075f;
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float MaxVelocity = 0.3f;
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float MinVelocity = -0.325f;
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float Bouncing = 0.07f;
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float Drag = 0.98f;
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float Size = 0.25f;
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float ThrowPower = 10f;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public ProtoId<CP14FishingProcessStyleSheetPrototype> Style = DefaultStyle;
}

View File

@@ -0,0 +1,18 @@
using JetBrains.Annotations;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.Fishing.Core.Behaviors;
[ImplicitDataDefinitionForInheritors, MeansImplicitUse]
[Serializable, NetSerializable]
public abstract partial class Behavior
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float Speed { get; set; } = 0.25f;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float Difficulty { get; set; } = 2f;
public abstract float CalculateSpeed(IRobustRandom random);
}

View File

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

View File

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

View File

@@ -0,0 +1,13 @@
using Robust.Shared.Random;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.Fishing.Core.Behaviors;
[Serializable, NetSerializable]
public sealed partial class MixedBehavior : Behavior
{
public override float CalculateSpeed(IRobustRandom random)
{
return Speed * (random.NextFloat() - 0.5f);
}
}

View File

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

View File

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

View File

@@ -0,0 +1,49 @@
using Content.Shared._CP14.Fishing.Core.Behaviors;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
namespace Content.Shared._CP14.Fishing.Core;
[Serializable, NetSerializable]
public sealed class Fish
{
private const float MaxPosition = 1f;
private const float MinPosition = 0f;
[ViewVariables(VVAccess.ReadWrite)]
public float Position { get; private set; }
[ViewVariables(VVAccess.ReadWrite)]
private readonly Behavior _behavior;
[ViewVariables(VVAccess.ReadWrite)]
private float _speed;
[ViewVariables(VVAccess.ReadWrite)]
private TimeSpan _updateSpeedTime;
public Fish(Behavior behavior, TimeSpan updateSpeedTime)
{
_behavior = behavior;
_updateSpeedTime = updateSpeedTime;
}
public void Update(float frameTime)
{
// Update position
Position += _speed * frameTime;
// Clamp position
Position = Math.Clamp(Position, MinPosition, MaxPosition);
}
public void UpdateSpeed(IRobustRandom random, IGameTiming timing)
{
if (_updateSpeedTime > timing.CurTime)
return;
_speed = _behavior.CalculateSpeed(random);
_updateSpeedTime = timing.CurTime + TimeSpan.FromSeconds(random.NextFloat(1.5f - 1f / _behavior.Difficulty, 2.5f - 1f / _behavior.Difficulty));
}
}

View File

@@ -0,0 +1,25 @@
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.Fishing.Core;
[Serializable, NetSerializable]
public sealed class Player
{
[ViewVariables(VVAccess.ReadWrite)]
public float Size;
[ViewVariables(VVAccess.ReadWrite)]
public float Position;
[ViewVariables(VVAccess.ReadWrite)]
public float Velocity;
[ViewVariables]
public float HalfSize => Size / 2f;
public Player(float size = 0.25f)
{
Size = size;
Position = HalfSize;
}
}

View File

@@ -0,0 +1,12 @@
namespace Content.Shared._CP14.Fishing.Events;
[ByRefEvent]
public readonly struct CP14FishingFinishedEvent
{
public readonly bool Success;
public CP14FishingFinishedEvent(bool success)
{
Success = success;
}
}

View File

@@ -0,0 +1,13 @@
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Fishing.Prototypes;
[Prototype("CP14FishingPoolLootTable")]
public sealed class CP14FishingPoolLootTablePrototype : IPrototype
{
[IdDataField]
public string ID { get; } = string.Empty;
[DataField]
public List<EntProtoId> Prototypes = [];
}

View File

@@ -0,0 +1,13 @@
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Fishing.Prototypes;
[Prototype("CP14FishingProcess")]
public sealed class CP14FishingProcessPrototype : IPrototype
{
[IdDataField]
public string ID { get; } = string.Empty;
[DataField, ViewVariables]
public EntProtoId LootProtoId;
}

View File

@@ -0,0 +1,127 @@
using System.Numerics;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Fishing.Prototypes;
/// <summary>
/// Represents the style sheet for the fishing process, containing UI elements like background and handle configurations.
/// </summary>
[Prototype("CP14FishingProcessStyleSheet")]
public sealed partial class CP14FishingProcessStyleSheetPrototype : IPrototype
{
/// <summary>
/// Gets the unique identifier for this fishing process style sheet prototype.
/// </summary>
[IdDataField]
public string ID { get; } = string.Empty;
/// <summary>
/// Background settings for the fishing process UI.
/// </summary>
[DataField, ViewVariables]
public BackgroundData Background = new();
/// <summary>
/// Handle settings for the fishing process UI.
/// </summary>
[DataField, ViewVariables]
public HandleData Handle = new();
/// <summary>
/// Contains data related to the background of the fishing process UI.
/// </summary>
[DataDefinition, Serializable]
public sealed partial class BackgroundData
{
/// <summary>
/// Path to the background texture image.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string Texture = "/Textures/_CP14/Interface/Fishing/background.png";
/// <summary>
/// Offset of the background texture in pixels.
/// </summary>
[DataField("offset"), ViewVariables(VVAccess.ReadWrite)]
public Vector2 OffsetPixels = new(10, 0);
/// <summary>
/// Offset of the handle in pixels.
/// </summary>
[DataField("handleOffset"), ViewVariables(VVAccess.ReadWrite)]
public Vector2 HandleOffsetPixels = new(16, 4);
/// <summary>
/// Size of the handle in pixels.
/// </summary>
[DataField("handleSize"), ViewVariables(VVAccess.ReadWrite)]
public Vector2 HandleSizePixels = new(149, 0);
/// <summary>
/// Offset of the progress bar in pixels.
/// </summary>
[DataField("progressOffset"), ViewVariables(VVAccess.ReadWrite)]
public Vector2 ProgressOffsetPixels = new(31, 3);
/// <summary>
/// Size of the progress bar in pixels.
/// </summary>
[DataField("progressSize"), ViewVariables(VVAccess.ReadWrite)]
public Vector2 ProgressSizePixels = new(4, 144);
/// <summary>
/// Gets the background offset in units (pixels divided by 32).
/// </summary>
[ViewVariables]
public Vector2 Offset => OffsetPixels / 32f;
/// <summary>
/// Gets the handle offset in units (pixels divided by 32).
/// </summary>
[ViewVariables]
public Vector2 HandleOffset => HandleOffsetPixels / 32f;
/// <summary>
/// Gets the progress bar offset in units (pixels divided by 32).
/// </summary>
[ViewVariables]
public Vector2 ProgressOffset => ProgressOffsetPixels / 32f;
/// <summary>
/// Gets the progress bar size in units (pixels divided by 32).
/// </summary>
[ViewVariables]
public Vector2 ProgressSize => ProgressSizePixels / 32f;
/// <summary>
/// Gets the handle size in units (pixels divided by 32).
/// </summary>
[ViewVariables]
public Vector2 HandleSize => HandleSizePixels / 32f;
}
/// <summary>
/// Contains data related to the handle elements of the fishing process UI.
/// </summary>
[DataDefinition, Serializable]
public sealed partial class HandleData
{
/// <summary>
/// Path to the texture for the top part of the handle.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string TopTexture = "/Textures/_CP14/Interface/Fishing/Handle/top.png";
/// <summary>
/// Path to the texture for the middle part of the handle.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string MiddleTexture = "/Textures/_CP14/Interface/Fishing/Handle/middle.png";
/// <summary>
/// Path to the texture for the bottom part of the handle.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string BottomTexture = "/Textures/_CP14/Interface/Fishing/Handle/bottom.png";
}
}

View File

@@ -0,0 +1,19 @@
using Content.Shared._CP14.Fishing.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Shared._CP14.Fishing.Systems;
public sealed class CP14FishingPoolSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public EntProtoId GetLootPrototypeId(Entity<CP14FishingPoolComponent> pool)
{
var lootTable = _prototype.Index(pool.Comp.LootTable);
var loot = _random.Pick(lootTable.Prototypes);
return loot;
}
}

View File

@@ -0,0 +1,43 @@
using Content.Shared._CP14.Fishing.Components;
using Content.Shared._CP14.Fishing.Core;
using Content.Shared._CP14.Fishing.Prototypes;
namespace Content.Shared._CP14.Fishing.Systems;
public abstract partial class CP14SharedFishingProcessSystem
{
protected Entity<CP14FishingRodComponent> GetRod(Entity<CP14FishingProcessComponent> process)
{
var entityUid = process.Comp.FishingRod!.Value;
var component = FishingRod.GetComponent(entityUid);
return (entityUid, component);
}
protected Entity<CP14FishingPoolComponent> GetPool(Entity<CP14FishingProcessComponent> process)
{
var entityUid = process.Comp.FishingPool!.Value;
var component = FishingPool.GetComponent(entityUid);
return (entityUid, component);
}
public CP14FishingProcessStyleSheetPrototype GetStyle(Entity<CP14FishingProcessComponent> process)
{
return GetStyle(GetRod(process));
}
public CP14FishingProcessStyleSheetPrototype GetStyle(Entity<CP14FishingRodComponent> fishingRod)
{
if (_prototype.TryIndex(fishingRod.Comp.Style, out var style))
return style;
Log.Error($"Failed to retrieve fishing rod style, {fishingRod.Comp.Style} not found. Reverting to default style.");
return _prototype.Index(CP14FishingRodComponent.DefaultStyle);
}
protected static bool Collide(Fish fish, Player player)
{
var playerMin = player.Position - player.HalfSize;
var playerMax = player.Position + player.HalfSize;
return fish.Position >= playerMin && fish.Position <= playerMax;
}
}

View File

@@ -0,0 +1,143 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared._CP14.Fishing.Components;
using Content.Shared._CP14.Fishing.Core;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Fishing.Systems;
public abstract partial class CP14SharedFishingProcessSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
protected EntityQuery<CP14FishingRodComponent> FishingRod;
protected EntityQuery<CP14FishingPoolComponent> FishingPool;
public override void Initialize()
{
base.Initialize();
FishingRod = GetEntityQuery<CP14FishingRodComponent>();
FishingPool = GetEntityQuery<CP14FishingPoolComponent>();
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<CP14FishingProcessComponent>();
while (query.MoveNext(out var entityUid, out var processComponent))
{
Update((entityUid, processComponent), frameTime);
}
}
private void UpdateReeling(Entity<CP14FishingProcessComponent> process,
Entity<CP14FishingRodComponent> fishingRod,
float frameTime)
{
if (process.Comp.Player is not { } player)
return;
if (fishingRod.Comp.Reeling)
{
player.Velocity += fishingRod.Comp.Speed * frameTime;
return;
}
player.Velocity -= fishingRod.Comp.Gravity * frameTime;
}
private void UpdateVelocity(Entity<CP14FishingProcessComponent> process,
Entity<CP14FishingRodComponent> fishingRod)
{
if (process.Comp.Player is not { } player)
return;
player.Velocity *= fishingRod.Comp.Drag;
player.Velocity = Math.Clamp(player.Velocity,
fishingRod.Comp.MinVelocity,
fishingRod.Comp.MaxVelocity);
}
private void UpdatePosition(Entity<CP14FishingProcessComponent> process,
float frameTime)
{
if (process.Comp.Player is not { } player)
return;
player.Position += process.Comp.Player.Velocity * frameTime;
var halfSize = process.Comp.Player.HalfSize;
process.Comp.Player.Position = Math.Clamp(process.Comp.Player.Position, halfSize, 1 - halfSize);
}
public void Update(Entity<CP14FishingProcessComponent> process, float frameTime)
{
if (process.Comp.Player is not { } player)
return;
var fishingRod = GetRod(process);
UpdateReeling(process, fishingRod, frameTime);
UpdateVelocity(process, fishingRod);
UpdatePosition(process, frameTime);
if (process.Comp.Fish is { } fish)
{
FishPreUpdate(process, fish, frameTime);
fish.Update(frameTime);
var collides = Collide(fish, player);
var progressAdditive = collides ? 0.1f : -0.2f;
process.Comp.Progress = Math.Clamp(process.Comp.Progress + progressAdditive * frameTime, 0, 1);
}
UpdateDirty(process);
if (process.Comp.Progress is 1 or 0)
Finish(process, process.Comp.Progress is 1);
}
public virtual void FishPreUpdate(Entity<CP14FishingProcessComponent> process, Fish fish, float frameTime)
{
}
public virtual void UpdateDirty(Entity<CP14FishingProcessComponent> process)
{
}
public virtual void Finish(Entity<CP14FishingProcessComponent> process, bool success)
{
}
public void Stop(Entity<CP14FishingProcessComponent> process)
{
var rod = GetRod(process);
rod.Comp.Process = null;
Dirty(rod);
Del(process);
}
public virtual void Reward(Entity<CP14FishingProcessComponent> process)
{
}
public bool TryGetByUser(EntityUid userEntityUid, [NotNullWhen(true)] out Entity<CP14FishingProcessComponent>? process)
{
process = null;
var query = EntityQueryEnumerator<CP14FishingProcessComponent>();
while (query.MoveNext(out var entityUid, out var processComponent))
{
if (processComponent.User != userEntityUid)
continue;
process = (entityUid, processComponent);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,51 @@
using Content.Shared._CP14.Fishing.Components;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.Fishing.Systems;
public abstract class CP14SharedFishingRodSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeAllEvent<RequestFishingRodReelMessage>(OnReel);
SubscribeLocalEvent<CP14FishingRodComponent, HandDeselectedEvent>(OnDeselected);
}
private void OnReel(RequestFishingRodReelMessage msg, EntitySessionEventArgs args)
{
var player = args.SenderSession.AttachedEntity;
if (!TryComp<HandsComponent>(player, out var hands))
return;
if (!TryComp<CP14FishingRodComponent>(hands.ActiveHandEntity, out var fishingRodComponent))
return;
if (fishingRodComponent.Reeling == msg.Reeling)
return;
fishingRodComponent.Reeling = msg.Reeling;
Dirty(hands.ActiveHandEntity.Value, fishingRodComponent);
}
private void OnDeselected(Entity<CP14FishingRodComponent> entity, ref HandDeselectedEvent args)
{
entity.Comp.Reeling = false;
Dirty(entity);
}
[Serializable, NetSerializable]
protected sealed class RequestFishingRodReelMessage : EntityEventArgs
{
public bool Reeling;
public RequestFishingRodReelMessage(bool reeling)
{
Reeling = reeling;
}
}
}

View File

@@ -0,0 +1,49 @@
- 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: CP14ModularCraftStartPoint
startSlots:
- FishingRodShaft
- 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

View File

@@ -9,6 +9,7 @@
snap:
- Wall
components:
- type: CP14FishingPool
- type: PlacementReplacement
key: floorTile
- type: Sprite

View File

@@ -0,0 +1,4 @@
- type: CP14FishingPoolLootTable
id: Default
prototypes:
- CP14BaseLockpick

View File

@@ -0,0 +1,13 @@
- type: CP14FishingProcessStyleSheet
id: Default
background:
texture: /Textures/_CP14/Interface/Fishing/Styles/Default/background.png
offset: 10, 0
handleOffset: 14, 5
handleSize: 11, 141
progressOffset: 4, 4
progressSize: 2, 142
handle:
topTexture: /Textures/_CP14/Interface/Fishing/Styles/Default/Handle/top.png
middleTexture: /Textures/_CP14/Interface/Fishing/Styles/Default/Handle/middle.png
bottomTexture: /Textures/_CP14/Interface/Fishing/Styles/Default/Handle/bottom.png

View File

@@ -0,0 +1,11 @@
- files:
- "/fish.png"
license: "CC-BY-NC-SA-3.0"
copyright: "@omsoyk (Discord)"
source: "https://github.com/crystallpunk-14/crystall-punk-14"
- files:
- "/default.png"
license: "CC-BY-NC-SA-3.0"
copyright: "@tornadotech (Discord), Tornado-Technology (Github)"
source: "https://github.com/crystallpunk-14/crystall-punk-14"

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

View File

@@ -0,0 +1,9 @@
- files:
- "/background.png"
- "Handle/top.png"
- "Handle/middle.png"
- "Handle/bottom.png"
license: "CC-BY-NC-SA-3.0"
copyright: "@omsoyk (Discord)"
source: "https://github.com/crystallpunk-14/crystall-punk-14"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

View File

@@ -0,0 +1,22 @@
{
"version": 1,
"size": {
"x": 48,
"y": 48
},
"license": "CLA",
"copyright": "Created by omsoyk (Discord) ",
"states": [
{
"name": "icon"
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B