How the Santa's Toy Factory Tycoon Loop Works
Tutorial intermediate compiles

How the Santa's Toy Factory Tycoon Loop Works

Updated intermediate Game Modes Verse Foundations Code verified

How the Santa's Toy Factory Tycoon Loop Works

Epic's LEGO® Santa's Toy Factory starter project is one of the most complete tycoon examples Epic ships — and its Verse is indexed here in the Library (SampleVerse/SantaToyFactory, attributed to Epic Games). This tutorial walks the core economic loop so you can reuse the pattern in your own tycoon: generators produce goods, goods sell for currency, currency buys upgrades, upgrades raise output — and the whole thing keeps running while the player is offline.

The code blocks below are quoted from the real sample. The one snippet under "Try it yourself" is a self-contained distillation you can compile on its own.

1. The currency: gold, guarded by failure

Everything is denominated in gold, stored per-player and mutated through three tiny functions in Persistence/player_info.verse. Note how SpendGold uses a failable expression to refuse an unaffordable purchase — the function simply fails (the <decides> effect) instead of returning an error code:

GrantGold<public>(Player:player, Amount:int)<decides><transacts>:void=
    CheckPlayerInfoForPlayer[Player]
    SourceInfo := PlayerInfoMap[Player]
    set PlayerInfoMap[Player] = player_info:
        Gold := SourceInfo.Gold + Amount
        MakePlayerInfo<constructor>(SourceInfo)

SpendGold<public>(Player:player, Amount:int)<decides><transacts>:void=
    CheckPlayerInfoForPlayer[Player]
    SourceInfo := PlayerInfoMap[Player]
    SourceInfo.Gold >= Amount        # <-- fails here if too poor; nothing is spent
    set PlayerInfoMap[Player] = player_info:
        Gold := SourceInfo.Gold - Amount
        MakePlayerInfo<constructor>(SourceInfo)

This is the single most important Verse idiom in the whole project: state changes are guarded by failable checks, so a failed SpendGold[...] leaves gold untouched. The caller wraps it in if (SpendGold[Player, Price]) { ... }.

2. Upgrade tiers come from data tables, not code

The progression curve lives entirely in Config/upgrade_config.verse as plain [][]int tables — one column per generator, one row per level:

FactoryBeltPrices: [][]int =
    array{  array{   1,    5,   10,   15},
            array{   5,   10,   25,   35},
            array{  10,   25,   50,  100},
            ... }   # 15 levels total

Because the balance is data, designers retune the economy without touching logic. The lookup helper clamps to the last row at max level and reads the price for the player's current level:

GetFactoryBeltUpgradePrice<public>(FactoryBeltNumber:int, Player:player)<decides><transacts>:int=
    FactoryBeltLevel := GetFactoryBeltLevel[Player, FactoryBeltNumber]
    FactoryBeltIndex := Min(FactoryBeltLevel, FactoryBeltPrices.Length-1)
    FactoryBeltPrices[FactoryBeltIndex][FactoryBeltNumber]

Upgrading is then just: price the next level, SpendGold, then UpgradeFactoryBeltLevel (which persists the new level). Belt speed is derived from level by a formula (FactoryBeltLevel * 0.25 + 0.25) so a higher level literally makes the line run faster.

3. Generators → product → orders → gold

The factory_manager (in Factory/factory_manager.verse) owns the belts, moulds, wrappers, and storage. When a player is selected as the factory owner, SelectPlayer propagates that owner to every element and starts running the line. Moulds stamp products onto belts, wrappers box them, storage holds them, and the order system (see Config/order_config.verse) buys finished products back for gold — closing the loop. New players get a scripted set of FirstOrders for a predictable tutorial, after which orders are generated randomly from whatever the player can currently produce.

4. Idle income: offline production

What makes it a tycoon rather than a clicker is that the factory keeps earning while you're gone. CalculateOfflineProduction reads a real-time clock (RealTime.GetDateAndTime()), measures the elapsed time since each mould's LatestProductionTime, divides by the mould's production interval, and clamps the result to when storage would have filled up:

CalculateOfflineProduction<public>():[]int=
    ...
    Now := RealTime.GetDateAndTime()
    ...
    TimeToProduce := Max(0.0, Min(NowTotalSeconds, TimeWhenFull) - (LatestProductionTimeTotalSeconds + DeliveryTime))
    Products := if (NowTotalSeconds > TimeWhenFull) then Round[TimeToProduce / ActualProductionTime] else Ceil[TimeToProduce / ActualProductionTime]
    ...
    OfflineProductionEvent.Signal(ProductsProducedOffline)

The key insight: don't simulate the missing hours tick-by-tick — compute the output analytically from elapsed time and the per-mould rate, capped by storage.

5. Persistence ties it together

All of this survives a session because the player's entire state is one class<final><persistable> (player_info) kept in a weak_map(player, player_info) — gold, every element's level, the current order, and timestamps. Updates use a copy-constructor so a change to one field rebuilds a fresh, fully-populated record. (See the companion tutorial, Persisting a Tycoon's State, for the full pattern.)

Try it yourself (compile-verified)

Here is a tiny, self-contained distillation of the price-table + guarded-purchase pattern. It compiles on its own in a UEFN project — paste it into a .verse file:

TryBuyUpgrade[100, 0, 1] succeeds and returns 75; TryBuyUpgrade[5, 0, 1] fails (can't afford the level-1 price of 25) — the same fail-don't-mutate discipline the real SpendGold uses.

Next steps

  • Browse the real files in the Library: Santa's Toy Factory — Upgrade Price Tables, Order Generation, Player Persistence, and the multi-file Tycoon Core (game loop).
  • Read the companion: Persisting a Tycoon's State with <persistable>.

Get the complete code — free

You've read the full walkthrough. The complete, copy-paste-ready Verse solution is free for members — sign in to unlock it.

Free with your BrainDead.TV / BrainDeadGuild Discord account. The walkthrough above is always free.

Verse source files

  • ·
  • ·
  • ·

Turn this into a guided course

Add Tycoon mechanics (Epic SampleVerse) to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.

Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.

Comments

    Sign in to vote, comment, or suggest an edit. Sign in