Skip to content

Gamble Features

Gamble features allow players to risk their winnings for a chance to multiply the payout. Configure wager features at the feature level in config.json, using either wagerFeatures or wagerStakeFeatures.

Gamble features are opt-in per game. Only games with wagerFeatures or wagerStakeFeatures defined in their config support wagering. Games without wager features auto-end the round. The engine credits the winnings automatically.

Two Wager Modes

wagerFeatures: Relative Multiplier

When the engine plays a spin in a wagerFeatures feature:

  1. The entry's win field acts as a multiplier on the player's accumulated winnings.
  2. win = 0 means the player loses everything.
  3. win = 2 means the player doubles their winnings.
  4. The player can collect() at any point during a wager feature to cash out.

Best for card gamble and ladder gamble games. These games have few wager steps. The player gambles the accumulated win in these games.

wagerStakeFeatures: Absolute Cashout Multiplier

When the engine plays a spin in a wagerStakeFeatures feature:

  1. The entry's win field is an absolute cashout multiplier relative to the original stake.
  2. win = 0 means the player loses everything.
  3. win = 1.75 means the player's cashout is 1.75x their stake.
  4. The player can collect() at any point to cash out.

Best for mines and frogger games. These games have many wager steps. Relative multipliers can compound rounding errors across many steps. This mode avoids that problem.

The engine triggers both types via featureAwards on base game entries. The engine handles them automatically during placeBet() continuation calls.

Configuration

The game's config.json lists wager features:

json
{
  "wagerFeatures": ["color-red", "color-black", "suit-hearts", "suit-diamonds"],
  "wagerStakeFeatures": ["mines_1_pick_1", "mines_1_pick_2"],
  "minWagerableWin": 1,
  "maxWagerableWin": 10000
}

A game can use both types at the same time. For example, mines progression can use wagerStakeFeatures. Card gamble in the same game can use wagerFeatures.

These feature entries live in the output files, together with base game entries and other feature entries.

Available Wager Features

The loadConfig response returns wager features:

typescript
const config = await loadConfig({ backendURL, token });
if (config.success) {
  const wagerFeatures = config.result.config.wagerFeatures;
  if (wagerFeatures) {
    console.log(wagerFeatures);
    // e.g. ["color-red", "color-black", "suit-hearts", ...]
  }
}

Game Flow

When a base game spin awards a win eligible for wagering, the engine sets canCollect = true. The engine also sends the available gamble options as playerChoice entries in engineData:

json
{
  "entryIndex": 1,
  "scenarioInfo": { "scenarioIndex": 34, "currentScenarioIndex": 0, "inProgress": false },
  "inProgress": true,
  "canCollect": true,
  "playerChoice": [
    { "feature": "step_1", "count": 1 },
    { "feature": "color-red", "count": 1 },
    { "feature": "color-black", "count": 1 },
    { "feature": "suit-clubs", "count": 1 },
    { "feature": "suit-diamonds", "count": 1 },
    { "feature": "suit-spades", "count": 1 },
    { "feature": "suit-hearts", "count": 1 }
  ]
}

Each playerChoice entry represents a gamble the player can take:

  • feature: the wager feature name (maps to feature entries)
  • count: number of spins (always 1 for gambles)

The player selects a gamble by sending playerChoiceIndex with placeBet(). This uses the same mechanism as any other player choice. Alternatively, the player can call collect() to cash out.

typescript
import { placeBet, collect } from '@hizi.io/engine-sdk';

// Base game spin triggers a wager feature via featureAwards
const spin = await placeBet({ backendURL, token, stake, config });

if (spin.success) {
  const { engineData } = spin.result.result;

  if (engineData.canCollect && engineData.playerChoice) {
    // Present the gamble options to the player
    for (let i = 0; i < engineData.playerChoice.length; i++) {
      const option = engineData.playerChoice[i];
      console.log(`Option ${i}: ${option.feature}`);
    }

    if (playerWantsToCollect) {
      // Cash out
      await collect({ backendURL, token });
    } else {
      // Player chose a gamble - send the selected index
      const chosenIndex = 2; // e.g. "color-black"
      const wagerSpin = await placeBet({ backendURL, token, playerChoiceIndex: chosenIndex, config });

      if (wagerSpin.success) {
        const { totalWin, engineData: nextState } = wagerSpin.result.result;

        if (totalWin === 0) {
          // Lost - round ends
        } else if (nextState.canCollect && nextState.playerChoice) {
          // Won - player can collect or gamble again
        }
      }
    }
  }
}

Integration Pattern

Base game spin

    ├── No wager feature → normal flow

    └── Wager feature triggered (canCollect === true, playerChoice present)

           ├── Player collects → collect({ backendURL, token })

           └── Player selects a gamble → placeBet({ backendURL, token, playerChoiceIndex: N })

                  ├── Won (totalWin > 0, canCollect + playerChoice again)
                  │      │
                  │      ├── Player collects → collect({ backendURL, token })
                  │      │
                  │      └── Player gambles again → placeBet({ ..., playerChoiceIndex: N })

                  └── Lost (totalWin === 0) → round ends

Next Steps