Skip to content

Commit

Permalink
Игральные карты + механика к ним. (#79)
Browse files Browse the repository at this point in the history
* Add playable cards

* SomeFixes

* SomeFixes2

* SomeFixes3

* Apply suggestions from code review

Co-authored-by: FN <[email protected]>

* статик статик хуестатик

* fix some

* meh

---------

Co-authored-by: AwareFoxy <[email protected]>
Co-authored-by: FN <[email protected]>
Co-authored-by: AwareFoxy <[email protected]>
  • Loading branch information
4 people authored and PvrG committed Nov 27, 2024
1 parent 13f4146 commit 3c73637
Show file tree
Hide file tree
Showing 245 changed files with 3,425 additions and 1 deletion.
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()
{

}

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();
[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

0 comments on commit 3c73637

Please sign in to comment.