Appearance
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:
- The entry's
winfield acts as a multiplier on the player's accumulated winnings. win = 0means the player loses everything.win = 2means the player doubles their winnings.- 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:
- The entry's
winfield is an absolute cashout multiplier relative to the original stake. win = 0means the player loses everything.win = 1.75means the player's cashout is 1.75x their stake.- 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 (always1for 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 endsNext Steps
- Response Handling - Full response structure including
playerChoice. - Error Handling - Handle errors during gameplay.
- Endpoints - Full endpoint reference.