mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 08:45:33 +00:00
222 lines
No EOL
5.6 KiB
C#
222 lines
No EOL
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Cirno.Scripts.Interactables;
|
|
using Cirno.Scripts.Resources;
|
|
using Cirno.Scripts.UI;
|
|
using Cirno.Scripts.Utils;
|
|
using Godot;
|
|
|
|
namespace Cirno.Scripts.Actors._3D;
|
|
|
|
[Tool]
|
|
public partial class VendingMachine3D : Interactable3D
|
|
{
|
|
public sealed class RuntimeShopEntry
|
|
{
|
|
public RuntimeShopEntry(VendingShopEntry entry)
|
|
{
|
|
Entry = entry;
|
|
RemainingQuantity = Math.Max(0, entry.StartingQuantity);
|
|
}
|
|
|
|
public VendingShopEntry Entry { get; }
|
|
|
|
public LootItem Item => Entry.Item;
|
|
|
|
public bool Unlimited => Entry.Unlimited;
|
|
|
|
public int RemainingQuantity { get; private set; }
|
|
|
|
public bool CanPurchase(int purchaseCount = 1)
|
|
{
|
|
return purchaseCount <= 0 || Unlimited || RemainingQuantity >= purchaseCount;
|
|
}
|
|
|
|
public bool TryConsume(int purchaseCount = 1)
|
|
{
|
|
if (purchaseCount <= 0 || Unlimited)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (RemainingQuantity < purchaseCount)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
RemainingQuantity -= purchaseCount;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
[Signal]
|
|
public delegate void ShopOpenedEventHandler();
|
|
|
|
[Signal]
|
|
public delegate void ShopClosedEventHandler();
|
|
|
|
[Export]
|
|
public PackedScene ShopUiScene { get; private set; } =
|
|
ResourceLoader.Load<PackedScene>("res://Scenes/HUD/VendingMachineShopUi.tscn");
|
|
|
|
[Export]
|
|
public VendingShopDefinition ShopDefinition { get; private set; } =
|
|
ResourceLoader.Load<VendingShopDefinition>("res://Resources/Shops/VendingMachine_Default.tres");
|
|
|
|
private readonly List<RuntimeShopEntry> _runtimeEntries = [];
|
|
private VendingMachineShopUi _activeShopUi;
|
|
private bool _runtimeInitialized;
|
|
|
|
public override void _Ready()
|
|
{
|
|
AddToGroup("Interactable");
|
|
|
|
if (Engine.IsEditorHint())
|
|
{
|
|
return;
|
|
}
|
|
|
|
EnsureRuntimeEntries();
|
|
}
|
|
|
|
public override bool CanActivate()
|
|
{
|
|
if (Engine.IsEditorHint())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
EnsureRuntimeEntries();
|
|
|
|
return !IsShopOpen()
|
|
&& ShopUiScene != null
|
|
&& _runtimeEntries.Count > 0
|
|
&& GameStateManager.Instance?.GameState is not GameState.Shop;
|
|
}
|
|
|
|
public override bool Activate(ActivationType activationType = ActivationType.Toggle)
|
|
{
|
|
if (Engine.IsEditorHint())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var typeToUse = activationType is ActivationType.Toggle ? ActivationType.Use : activationType;
|
|
if (typeToUse is not ActivationType.Use)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!MeetsRequirements() || !CanActivate())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
EnsureRuntimeEntries();
|
|
|
|
if (GameStateManager.Instance == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
GameStateManager.Instance.ChangeState(GameState.Shop);
|
|
|
|
_activeShopUi = ShopUiScene.Instantiate<VendingMachineShopUi>();
|
|
_activeShopUi.Init(this);
|
|
_activeShopUi.Closed += OnShopUiClosed;
|
|
|
|
var parent = GetTree().CurrentScene ?? GetTree().Root;
|
|
parent.AddChild(_activeShopUi);
|
|
|
|
EmitSignal(SignalName.ShopOpened);
|
|
return true;
|
|
}
|
|
|
|
public override void _ExitTree()
|
|
{
|
|
if (IsInstanceValid(_activeShopUi))
|
|
{
|
|
_activeShopUi.Closed -= OnShopUiClosed;
|
|
_activeShopUi.QueueFree();
|
|
}
|
|
|
|
_activeShopUi = null;
|
|
}
|
|
|
|
public IReadOnlyList<RuntimeShopEntry> GetEntries()
|
|
{
|
|
EnsureRuntimeEntries();
|
|
return _runtimeEntries;
|
|
}
|
|
|
|
public RuntimeShopEntry FindEntry(StringName itemKey)
|
|
{
|
|
EnsureRuntimeEntries();
|
|
return _runtimeEntries.FirstOrDefault(entry => entry.Item?.ItemKey == itemKey);
|
|
}
|
|
|
|
public bool TryConsumeStock(StringName itemKey, int purchaseCount = 1)
|
|
{
|
|
var entry = FindEntry(itemKey);
|
|
return entry?.TryConsume(purchaseCount) ?? false;
|
|
}
|
|
|
|
// public void _func_godot_apply_properties(Godot.Collections.Dictionary props)
|
|
// {
|
|
// if (props.TryGetValue("shop_definition_path", out var shopDefinitionPath))
|
|
// {
|
|
// var path = shopDefinitionPath.AsString();
|
|
// if (!string.IsNullOrWhiteSpace(path))
|
|
// {
|
|
// var loadedDefinition = ResourceLoader.Load<VendingShopDefinition>(path);
|
|
// if (loadedDefinition != null)
|
|
// {
|
|
// ShopDefinition = loadedDefinition;
|
|
// _runtimeInitialized = false;
|
|
// }
|
|
// else
|
|
// {
|
|
// GD.PrintErr($"Failed to load vending shop definition from '{path}'");
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
private void EnsureRuntimeEntries()
|
|
{
|
|
if (_runtimeInitialized)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_runtimeInitialized = true;
|
|
_runtimeEntries.Clear();
|
|
|
|
if (ShopDefinition == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var entry in ShopDefinition.Entries.Where(entry => entry?.Item != null))
|
|
{
|
|
_runtimeEntries.Add(new RuntimeShopEntry(entry));
|
|
}
|
|
}
|
|
|
|
private bool IsShopOpen()
|
|
{
|
|
return IsInstanceValid(_activeShopUi);
|
|
}
|
|
|
|
private void OnShopUiClosed()
|
|
{
|
|
if (IsInstanceValid(_activeShopUi))
|
|
{
|
|
_activeShopUi.Closed -= OnShopUiClosed;
|
|
}
|
|
|
|
_activeShopUi = null;
|
|
EmitSignal(SignalName.ShopClosed);
|
|
}
|
|
} |