Skip to content

Gamble Features

Gamble features allow players to risk their winnings for a chance to multiply the payout. Wager features are configured 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 and credit 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, ladder gamble — games with few wager steps where the player gambles their accumulated win.

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, frogger — multi-step progression games with many wager steps. This mode avoids compounding rounding errors that accumulate when applying relative multipliers across many steps.

Both types are triggered via featureAwards on base game entries and handled automatically during placeBet() continuation calls.

Configuration

Wager features are listed in the game's config.json:

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 simultaneously — e.g., mines progression via wagerStakeFeatures combined with card gamble via wagerFeatures.

These feature entries live in the output files alongside basegame and other features.

Available Wager Features

Wager features are returned in the loadConfig response:

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 and 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(), using 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 });

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 });

      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