Editorial illustration: Changing coins in one place

Changing coins in one place

The problem I needed to solve

Once rewards and purchases appeared, editing coins directly from several screens could separate balances from statistics. I centralized additions and spending in one service.

Implementation in this snapshot

CurrencyService.AddCoins increases the balance and totalCoinsEarned. TrySpendCoins checks CanAfford before changing the balance and totalCoinsSpent; both persist and emit CoinsChanged.

The design decision and its cost

CurrencyChangeReason explains the change, and GameplayTelemetry receives it too. The header can react without becoming the owner of coin accounting.

Current boundaries

This is local integer-based accounting, without concurrency locking or server validation. SetCoinsForDebug is a separate path that does not rewrite lifetime earning and spending totals.

Review scenarios and contract meaning

Consider a hypothetical balance of one hundred coins and a purchase costing thirty. These are explanatory numbers, not player data. A successful purchase should leave seventy and increase lifetime spending by thirty. If the shop only changes the displayed number, spending-based achievements and the next save will disagree. TrySpendCoins keeps these effects together. A price above the available balance must be rejected before data changes so that the interface can explain the failure.

In the code, nonpositive spending succeeds without a debit, while nonpositive additions do nothing. That detail leaves an important responsibility with item definition validation: a successful call for zero does not establish correct pricing. The debug path changes the balance without reconstructing earning or spending history. When reviewing reports or testing achievements, I therefore need to distinguish ordinary gameplay from development tools. A central service simplifies local consistency, but tampered files or concurrent devices require another contract.

A balance change differs from the final balance. A reward followed by a purchase may return to the starting number while two real actions occurred. Each reason and delta matters for understanding the economy. The service makes them expressible, but a local event alone does not establish long-term auditing or reconciliation with an independent authority.

What this stage taught me

For me, the coin number became easier to trust when every change had an explicit reason and path. That foundation mattered for entry fees, rewards and customization before the store’s appearance.

Explore Dalo

Latest devlogs

Editorial illustration: Pasur launch and telemetry in the shared structure

Pasur launch and telemetry in the shared structure

Adding Pasur needs both a correct mode handoff and valid public telemetry.

Read article
Editorial illustration: Presenting selection and captures in Pasur

Presenting selection and captures in Pasur

Pasur motion should explain which hand card was played and which table cards were captured.

Read article
Editorial illustration: Pasur bot decisions from capture options

Pasur bot decisions from capture options

My teammate’s Pasur bot chooses among legal options without inspecting hidden opposing cards.

Read article
Dalo