Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Игральные карты + механика к ним. #79

Merged
merged 8 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions Content.Client/_CorvaxNext/Cards/Card/CardSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System.Linq;
using Content.Shared._CorvaxNext.Cards.Card;
using Robust.Client.GameObjects;
using Robust.Shared.Utility;

namespace Content.Client._CorvaxNext.Cards.Card;

/// <summary>
/// Handles the initialization and updating of card sprites on the client side,
/// particularly when a card is flipped or when the component starts up.
/// </summary>
public sealed class CardSystem : EntitySystem
{
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<CardComponent, ComponentStartup>(OnComponentStartupEvent);
SubscribeNetworkEvent<CardFlipUpdatedEvent>(OnFlip);
}

private void OnComponentStartupEvent(EntityUid uid, CardComponent comp, ComponentStartup args)
{
if (!TryComp(uid, out SpriteComponent? spriteComponent))
return;

var layerCount = spriteComponent.AllLayers.Count();
for (var i = 0; i < layerCount; i++)
{
if (!spriteComponent.TryGetLayer(i, out var layer) || layer.State == null || layer.State.Name == null)
continue;

var rsi = layer.RSI ?? spriteComponent.BaseRSI;
if (rsi == null)
continue;

comp.FrontSprite.Add(new SpriteSpecifier.Rsi(rsi.Path, layer.State.Name));
}

comp.BackSprite ??= comp.FrontSprite;

// Removed Dirty(uid, comp); as calling Dirty on the client is inappropriate.
UpdateSprite(uid, comp);
}

private void OnFlip(CardFlipUpdatedEvent args)
{
var entity = GetEntity(args.Card);
if (!TryComp(entity, out CardComponent? comp))
return;

UpdateSprite(entity, comp);
}

private void UpdateSprite(EntityUid uid, CardComponent comp)
{
var newSprite = comp.Flipped ? comp.BackSprite : comp.FrontSprite;
if (newSprite == null)
return;

if (!TryComp(uid, out SpriteComponent? spriteComponent))
return;

var layerCount = newSprite.Count;
var spriteLayerCount = spriteComponent.AllLayers.Count();

// Inserts missing layers
if (spriteLayerCount < layerCount)
{
for (var i = spriteLayerCount; i < layerCount; i++)
{
spriteComponent.AddBlankLayer(i);
}
}
// Removes extra layers
else if (spriteLayerCount > layerCount)
{
for (var i = spriteLayerCount - 1; i >= layerCount; i--)
{
spriteComponent.RemoveLayer(i);
}
}

for (var i = 0; i < layerCount; i++)
{
var layer = newSprite[i];
spriteComponent.LayerSetSprite(i, layer);
}
}
}
85 changes: 85 additions & 0 deletions Content.Client/_CorvaxNext/Cards/CardSpriteSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System.Linq;
using Content.Shared._CorvaxNext.Cards.Stack;
using Robust.Client.GameObjects;

namespace Content.Client._CorvaxNext.Cards;

/// <summary>
/// Manages the visual representation of card stacks by dynamically adjusting and configuring sprite layers
/// based on the number of cards in the stack and their properties.
/// </summary>
public sealed class CardSpriteSystem : EntitySystem
{
/// <inheritdoc/>
public override void Initialize()
{

}
AwareFoxy marked this conversation as resolved.
Show resolved Hide resolved

public bool TryAdjustLayerQuantity(Entity<SpriteComponent, CardStackComponent> uid, int? cardLimit = null)
{
var sprite = uid.Comp1;
var stack = uid.Comp2;
var cardCount = cardLimit == null ? stack.Cards.Count : Math.Min(stack.Cards.Count, cardLimit.Value);

var layerCount = 0;
//Gets the quantity of layers
foreach (var card in stack.Cards.TakeLast(cardCount))
{
if (!TryComp(card, out SpriteComponent? cardSprite))
return false;

layerCount += cardSprite.AllLayers.Count();
}
//inserts Missing Layers
if (sprite.AllLayers.Count() < layerCount)
{
for (var i = sprite.AllLayers.Count(); i < layerCount; i++)
{
sprite.AddBlankLayer(i);
}
}
//Removes extra layers
else if (sprite.AllLayers.Count() > layerCount)
{
for (var i = sprite.AllLayers.Count() - 1; i >= layerCount; i--)
{
sprite.RemoveLayer(i);
}
}


return true;
}

public bool TryHandleLayerConfiguration(Entity<SpriteComponent, CardStackComponent> uid, int cardCount, Func<Entity<SpriteComponent>, int, int, bool> layerFunc)
{
var sprite = uid.Comp1;
var stack = uid.Comp2;

// int = index of what card it is from
List<(int, ISpriteLayer)> layers = [];

var i = 0;
foreach (var card in stack.Cards.TakeLast(cardCount))
{
if (!TryComp(card, out SpriteComponent? cardSprite))
return false;
layers.AddRange(cardSprite.AllLayers.Select(layer => (i, layer)));
i++;
}

var j = 0;
foreach (var obj in layers)
{
var (cardIndex, layer) = obj;
sprite.LayerSetVisible(j, true);
sprite.LayerSetTexture(j, layer.Texture);
sprite.LayerSetState(j, layer.RsiState.Name);
layerFunc.Invoke((uid, sprite), cardIndex, j);
j++;
}

return true;
}
}
162 changes: 162 additions & 0 deletions Content.Client/_CorvaxNext/Cards/Deck/CardDeckSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
using System.Collections.Generic;
using System.Numerics;
using Content.Shared._CorvaxNext.Cards.Deck;
using Content.Shared._CorvaxNext.Cards.Stack;
using Robust.Client.GameObjects;

namespace Content.Client._CorvaxNext.Cards.Deck;

/// <summary>
/// Handles the visual representation and sprite updates for card decks on the client side,
/// responding to events such as card stack changes, flips, and reordering.
/// </summary>
public sealed class CardDeckSystem : EntitySystem
{
private readonly Dictionary<EntityUid, int> _notInitialized = new();
AwareFoxy marked this conversation as resolved.
Show resolved Hide resolved
[Dependency] private readonly CardSpriteSystem _cardSpriteSystem = default!;

/// <inheritdoc/>
public override void Initialize()
{
UpdatesOutsidePrediction = false;
SubscribeLocalEvent<CardDeckComponent, ComponentStartup>(OnComponentStartupEvent);
SubscribeNetworkEvent<CardStackInitiatedEvent>(OnStackStart);
SubscribeNetworkEvent<CardStackQuantityChangeEvent>(OnStackUpdate);
SubscribeNetworkEvent<CardStackReorderedEvent>(OnReorder);
SubscribeNetworkEvent<CardStackFlippedEvent>(OnStackFlip);
SubscribeLocalEvent<CardDeckComponent, AppearanceChangeEvent>(OnAppearanceChanged);
}

public override void Update(float frameTime)
{
base.Update(frameTime);

// Lazy initialization of card deck sprites
var entitiesToRemove = new List<EntityUid>();

foreach (var kvp in _notInitialized)
{
var uid = kvp.Key;
var attempts = kvp.Value;

if (attempts >= 5)
{
// Maximum attempts reached, remove from tracking
entitiesToRemove.Add(uid);
continue;
}

_notInitialized[uid] = attempts + 1;

if (!TryComp(uid, out CardStackComponent? stack) || stack.Cards.Count <= 0)
continue;

// Check if the card's sprite layer is initialized
if (!TryGetCardLayer(stack.Cards[^1], out _))
continue;

// Update the sprite now that the card is initialized
if (TryComp(uid, out CardDeckComponent? comp))
{
UpdateSprite(uid, comp);
}

entitiesToRemove.Add(uid);
}

// Remove entities outside the loop to avoid modifying the collection during iteration
foreach (var uid in entitiesToRemove)
{
_notInitialized.Remove(uid);
}
}

private bool TryGetCardLayer(EntityUid card, out SpriteComponent.Layer? layer)
{
layer = null;
if (!TryComp(card, out SpriteComponent? cardSprite))
return false;

if (!cardSprite.TryGetLayer(0, out var l))
return false;

layer = l;
return true;
}

private void UpdateSprite(EntityUid uid, CardDeckComponent comp)
{
if (!TryComp(uid, out SpriteComponent? sprite))
return;

if (!TryComp(uid, out CardStackComponent? cardStack))
return;

// Prevent errors when the card stack is empty or not initialized
if (cardStack.Cards.Count <= 0 || !TryGetCardLayer(cardStack.Cards[^1], out _))
{
_notInitialized[uid] = 0;
return;
}

_cardSpriteSystem.TryAdjustLayerQuantity((uid, sprite, cardStack), comp.CardLimit);

_cardSpriteSystem.TryHandleLayerConfiguration(
(uid, sprite, cardStack),
comp.CardLimit,
(sprt, cardIndex, layerIndex) =>
{
sprite.LayerSetRotation(layerIndex, Angle.FromDegrees(90));
sprite.LayerSetOffset(layerIndex, new Vector2(0, comp.YOffset * cardIndex));
sprite.LayerSetScale(layerIndex, new Vector2(comp.Scale, comp.Scale));
return true;
}
);
}

private void OnStackUpdate(CardStackQuantityChangeEvent args)
{
var entity = GetEntity(args.Stack);
if (!TryComp(entity, out CardDeckComponent? comp))
return;

UpdateSprite(entity, comp);
}

private void OnStackFlip(CardStackFlippedEvent args)
{
var entity = GetEntity(args.CardStack);
if (!TryComp(entity, out CardDeckComponent? comp))
return;

UpdateSprite(entity, comp);
}

private void OnReorder(CardStackReorderedEvent args)
{
var entity = GetEntity(args.Stack);
if (!TryComp(entity, out CardDeckComponent? comp))
return;

UpdateSprite(entity, comp);
}

private void OnAppearanceChanged(EntityUid uid, CardDeckComponent comp, AppearanceChangeEvent args)
{
UpdateSprite(uid, comp);
}

private void OnComponentStartupEvent(EntityUid uid, CardDeckComponent comp, ComponentStartup args)
{
UpdateSprite(uid, comp);
}

private void OnStackStart(CardStackInitiatedEvent args)
{
var entity = GetEntity(args.CardStack);
if (!TryComp(entity, out CardDeckComponent? comp))
return;

UpdateSprite(entity, comp);
}
}
Loading
Loading