Currencies (Wallet)

The Currencies sub-asmdef of com.cupkekgames.resources provides a global, save-data-scoped wallet keyed by currency id.

  • Assembly: CupkekGames.Resources.Currencies
  • Namespace: CupkekGames.Resources.Currencies
  • Deps: com.cupkekgames.data, com.cupkekgames.services

Types

TypeRole
Currency (struct)(string Id, long Amount) transient pair — used as drop result, event payload, or transactional descriptor
CurrencyDefinitionSOPer-currency ScriptableObject — display name, icon, max amount, format string
CurrencyCatalogAssetCatalog<CurrencyDefinitionSO>. Register the catalog asset with _catalogId = "Currencies" (see CurrencyConstants.CurrenciesCatalogId)
WalletIData runtime store. Get / Set / Add / Spend / Has / CanAfford + OnChanged(id, old, new) event
CurrencyConstantsHolds the canonical "Currencies" catalog id

Authoring

  1. Create one CurrencyDefinitionSO per currencyCreate → CupkekGames/Resources/Currency Definition. Set display name, icon, optional max amount, format string (e.g. "N0" for 1,240).
  2. Create one CurrencyCatalog asset — Create → CupkekGames/Resources/Catalog/Currencies. Set _catalogId = "Currencies". Drag the definition assets into its database.
  3. Place the catalog in a ServiceRegistrySO so it registers itself on scene/init load.

The asset name of each CurrencyDefinitionSO doubles as its id. Match the asset name to the stable id you'll use everywhere (Gold.assetWallet.Get("Gold")).

Runtime

csharp
using CupkekGames.Resources.Currencies; // Wallet lives on your save data (or wherever player-scoped state goes). public class MyGameSaveData : IGameSaveData, IData { public Wallet Wallet = new(); // ... } // Earn: saveData.Wallet.Add("Gold", 50); // OnChanged fires (id, old, new) // Spend: if (saveData.Wallet.Spend("Gold", 100)) BuyItem(); else ShowInsufficientFunds(); // Query: long gold = saveData.Wallet.Get("Gold"); bool affordable = saveData.Wallet.CanAfford("Diamond", 5);

Wallet uses long storage so idle-game-scale balances don't overflow.

UI binding

Subscribe to Wallet.OnChanged from your binder. The event fires on Set, Add, and successful Spend:

csharp
saveData.Wallet.OnChanged += (id, oldValue, newValue) => { var label = chipsByCurrency[id]; AnimateCountUp(label, oldValue, newValue); };

No polling required.

Drop-table routing

DropTable.Evaluate returns List<DropResult> where each result has a CatalogKey + Amount. A drop entry pointing at Currencies/Gold (catalog "Currencies", key "Gold") with Chance: 1.0, MinAmount: 10, MaxAmount: 50 is valid markup — the consumer just routes by result.Key.Catalog:

csharp
foreach (var result in drops) { if (result.Key.Catalog == CurrencyConstants.CurrenciesCatalogId) wallet.Add(result.Key.Key, result.Amount); else inventory.AddItem(...); }

No changes to DropTable are needed — it's already polymorphic over catalog id.

Save semantics

Wallet implements IData:

  • CloneData() → deep copy of the balance dictionary (no service-locator calls — safe for the default→actual reset pattern documented under DataSO workflows)
  • Validate() → always returns true (no invariants beyond "Dictionary is well-formed")
  • OnAfterDeserialize() → no-op (Wallet stores primitives only)

Serialize via your project's IDataSerializer (e.g. com.cupkekgames.newtonsoft).

Display formatting

Each CurrencyDefinitionSO carries a FormatString field (.NET format string, default "N0"). Use it for label display:

csharp
var def = currencyCatalog.GetValue("Gold"); string display = def.Beautify(saveData.Wallet.Get("Gold")); // "1,240"

This keeps formatting per-currency (e.g. "1,234 Gold" vs "1.234M Energy") without UI code knowing the rules.

Settings

Theme

Light

Contrast

Material

Dark

Dim

Material Dark

System

Sidebar(Light & Contrast only)

Light
Dark

Font Family

DM Sans

Wix

Inclusive Sans

AR One Sans

Direction

LTR
RTL