Table of contents

Overview

SLOT-IDE is a web based IDE that let's you define game scripts and run them server side through the game engine.

By choosing the desired running mode you can execute theoretical calculations (including the generation of reel strips) or run simulations of the game defined in the script.

As a result of theoretical calculations a PAR SHEET is automatically generated and displayed. If instead you are running a simulation at the end of the process you will get a detailed simulation report.

Scripts defined in the IDE don't necessarily have to define games, they can also define classes and functions that you can import and use in your game scripts.

Scripts are written in javascript, although most game scripts hardly contain any code and the majority of games can be entirely defined through a simple configuration syntax. This means that if you are unfamiliar with javascript you don't need to worry and you will still be able to use the IDE just by learning how define your games through the configuration.
When your script defines no game, you can still run it and get console output from it, this is useful for testing individual bits of code.

If your game script contains code and dynamic parts you can run it in debug mode, set breakpoints and inspect variables and code as it runs, so you can make sure it is doing what's expected.

Defining games

Games are defined through a JSON based configuration. If you aren't familiar with JSON, all you need to know is that it is a powerful and compact way to express objects by listing their properties and values. Objects are enclosed by curly brackets, the list of properties comes as a comma separated list of property: value pairs. Values can be of any datatype, such as numbers, strings or arrays. Arrays are enclosed by square brackets containing the elements separated by a comma.

In order to define the game in your script, you need to provide the configuration object that defines your game as an argument to the game constructor, as shown in the following code snippet:
new Game({
    symbols: [
        {name: 'Wild', isWild:true}, 
        'Picture1', 'Picture2', 'Picture3', 'Nine', 'Ten',
        'Jack', 'Queen', 'King', 'Ace', 
        {name: 'Scatter', wildReplace: false}
    ],
    reelFreqs: {                                
        'Wild':      [1,1,1,1,1],
        'Picture1':  [2,3,2,2,3],
        'Picture2':  [2,3,3,3,4],
        'Picture3':  [3,3,3,2,3],
        'Nine':      [3,3,3,4,4],
        'Ten':       [4,2,3,3,3],
        'Jack':      [4,3,4,3,4],
        'Queen':     [3,4,4,4,3],
        'King':      [4,4,4,5,3],
        'Ace':       [4,5,4,4,3],
        'Scatter':   [2,1,1,1,1]               
    },
    paytable: [        
        {on: {occurs:[2,3,4,5], of:'Wild',   mode:'line'}, pay: [5,50,500,5000]},
        {on: {occurs:[2,3,4,5], of:'Picture1',   mode:'line'}, pay: [3,40,200,1000]},
        {on: {occurs:[2,3,4,5], of:'Picture2',   mode:'line'}, pay: [2,30,150,500]},
        {on: {occurs:[2,3,4,5], of:'Picture3',   mode:'line'}, pay: [2,25,100,300]},
        {on: {occurs:[3,4,5], of:'Nine',   mode:'line'}, pay: [20,75,200]},
        {on: {occurs:[3,4,5], of:'Ten',   mode:'line'}, pay: [20,75,200]},
        {on: {occurs:[3,4,5], of:'Jack',   mode:'line'}, pay: [15,50,100]},
        {on: {occurs:[3,4,5], of:'Queen',   mode:'line'}, pay: [15,50,100]},
        {on: {occurs:[3,4,5], of:'King',   mode:'line'}, pay: [10,25,50]},
        {on: {occurs:[3,4,5], of:'Ace',   mode:'line'}, pay: [10,25,50]},
        {on: {occurs:[3,4,5], of:'Scatter',   mode:'scatter'}, pay: [5,25,100], trigger: 'freespins'}
    ],
    bonus: {
	    freespins: {
		    spins: 10, multiplier: 3
	    }
    }
});

Symbols

The symbols of your game need to be provided in a property called symbols as an array. Each symbol can either be a string carrying the symbol name or, for more complex symbols, an object. In the latter case the name of the symbol must be specified in the name property.
Here is the list of supported symbols properties and their meaning:
  • isWild: boolean flag indicating whether the symbol is wild and can substitute for other symbols. Defaults to false
  • wildReplace: determines whether the symbol can be substituted by wild symbols. The value can either be boolean, an array or a string. if true then the symbol can be substituted by any wild, if false the symbol cannot be substituted by any wild symbol. If the value is an array then it must specify the list of wild symbol names that can substitute for this symbol. A string value can be used to let the symbol be replaced by wild symbols only for specific paymodes (this is useful in situations where the same symbol pays both as a scatter and on the paylines, then by setting the value of wildReplace to 'line' the symbol will be replaced by wild symbols only for line pays). Defaults to true
  • wildMultipliers: array that specifies the multipliers to be applied when this symbol substitutes for other symbols. Can only be used when isWild is true. Values in the array are multipliers to be applied when a winning combination is obtained with the corresponding number of wild substitutions (first value in the array is the multiplier for one wild substitution and so on..). For a specific number of substitutions the highest possible multiplier is applied (e.g. providing wildMultipliers: [2, 4, 8] means apply 2x multiplier for one wild substitution, 4x multiplier for two wild substitutions, 8x multiplier for winning combinations obtained with three or more wild substitutions).
  • expand: array that specifies the reels on which the symbol acts as an expanding wild. If the symbol expands on a reel, anytime it appears it will replace all other visible symbols on the same reel. The array must contain the (0-based) index of each reel you want the symbol to expand on (e.g. if expand: [0, 2] then the symbol expands on the first and third reels). Can only be used when isWild is true.

Reel strips

It is not mandatory to define the reel strips of the game, for instance you may want the engine to generate the reel strips for you, based on your requirements (see next section).
Reel strips can be defined by either entering the frequencies of the symbols on each reel or by providing the complete reel strips.
If you provide the symbol frequencies the engine works out the corresponding reel strips itself. As shown in the example game configuration above you do this by providing a property called reelFreqs. The value of the property is an object whose keys are the symbol names while values are arrays containing the number of times a symbol appears on the corresponding reel starting from the left-most one.

You provide the complete reel strips using a property called reels. The value of this property is an array of arrays, each array listing the symbols of each reel starting from the left-most one.
The following configuration snippet shows you what the reels property looks like:
reels:[
 ['Picture3', 'Picture1', 'Scatter', 'Picture3', 'Ace', 'Queen', 'Queen', 'Wild', ...],
 ['Ace', 'King', 'Scatter', 'Nine', 'Ace', 'Ace', 'Ten', 'Picture1', ...],
 ['King', 'Jack', 'Scatter', 'Nine', 'Nine', 'King', 'Picture3', 'Picture2', 'King', ...],
 ['King', 'Queen', 'Scatter', 'King', 'Picture3', 'Ace', 'Ace', 'Jack', ...],
 ['King', 'Jack', 'Scatter', 'Nine', 'Nine', 'King', 'Picture3', 'Picture2', 'King', ...]
]

Mixed reel strips

You can let your game use multiple set of reel strips by specifying them in a probability table as shown here below:
reels: [
        {prob:0.8, value: [
            ["Butter","Eggs","Scale","Mayonnaise","Eggs","Scale","Sausage","Cheese"...],
            ["Butter","Butter","Scale","Butter","Bacon","Bacon","Steak","Mayonnaise"...],
            ["Bacon","Sausage","Scale","Cheese","Drumstick","Bacon","Cheese","Sausage"...],
            ["Sausage","Bacon","Scale","Sausage","Cheese","Mayonnaise","Cheese","Drumstick"...],
            ["Bacon","Butter","Scale","Butter","Eggs","Drumstick","Butter","Steak","Eggs"...]
        ]},
        
        {prob:0.2, value: [
			["Butter","Eggs","Scale","Mayonnaise","Eggs","Scale","Sausage","Cheese","Butter"],
        	["Butter","Butter","Scale","Butter","Bacon","Bacon","Steak","Mayonnaise","Mayonnaise"],
        	["Bacon","Sausage","Scale","Cheese","Drumstick","Bacon","Cheese","Sausage","Butter"],
        	["Sausage","Bacon","Scale","Sausage","Cheese","Mayonnaise","Cheese","Drumstick"],
        	["Bacon","Butter","Scale","Butter","Eggs","Drumstick","Butter","Steak","Eggs"]
        ]}
    ]
...
In the following example two sets of reel strips are defined by providing the symbols frequencies. In this case the two sets have equal chance to be picked. Each set is labeled using 'name' attribute. When specified, the name is used to refer to specific reel set in the generated excels.
reelFreqs: [
    {prob: 0.5, name: 'NormalSet', value: {                                
        'Atkins':    [1,1,1,1,1],
        'Steak':     [2,3,2,2,3],
        'Ham':       [2,3,3,3,4],
        'Drumstick': [3,3,3,2,3],
        'Sausage':   [3,3,3,4,4],
        'Eggs':      [4,2,3,3,3],
        'Butter':    [4,3,4,3,4],
        'Cheese':    [3,4,4,4,3],
        'Bacon':     [4,4,4,5,3],
        'Mayonnaise':[4,5,4,4,3],
        'Scale':     [2,1,1,1,1]               
    }}, 
    {prob: 0.5, name: 'NoWildSet', value: {                                
        'Atkins':    [0,0,0,0,0],
        'Steak':     [2,3,2,2,3],
        'Ham':       [2,3,3,3,4],
        'Drumstick': [3,3,3,2,3],
        'Sausage':   [3,3,3,4,4],
        'Eggs':      [4,2,3,3,3],
        'Butter':    [4,3,4,3,4],
        'Cheese':    [3,4,4,4,3],
        'Bacon':     [4,4,4,5,3],
        'Mayonnaise':[4,5,4,4,3],
        'Scale':     [2,1,1,1,1]               
    }}]
...

Reel strips generation

If you provide no reels in your game configuration, you can ask the engine to generate reel strips for you. You do so by providing an additional property called rtp where you specify your requirements for the reel strips in terms of theoretical payback percentage.
The value of this property can either be a number or an object. The object enables you to enter more than one constraint, each property of the object is a constraint for the reel strips generation.

The following example shows you how to generate a simple slot game (with no bonuses) that has a theoretical payback of 91.21%:

new Game({
    symbols: [
        {name: 'Wild', isWild:true}, 
        'Picture1', 'Picture2', 'Picture3', 'Nine', 'Ten',
        'Jack', 'Queen', 'King', 'Ace', 
        {name: 'Scatter', wildReplace: false} 
    ],
    rtp: 0.9121,
    paytable: [        
        {on: {occurs:[2,3,4,5], of:'Wild',   mode:'line'}, pay: [5,50,500,5000]},
        {on: {occurs:[2,3,4,5], of:'Picture1',   mode:'line'}, pay: [3,40,200,1000]},
        {on: {occurs:[2,3,4,5], of:'Picture2',   mode:'line'}, pay: [2,30,150,500]},
        {on: {occurs:[2,3,4,5], of:'Picture3',   mode:'line'}, pay: [2,25,100,300]},
        {on: {occurs:[3,4,5], of:'Nine',   mode:'line'}, pay: [20,75,200]},
        {on: {occurs:[3,4,5], of:'Ten',   mode:'line'}, pay: [20,75,200]},
        {on: {occurs:[3,4,5], of:'Jack',   mode:'line'}, pay: [15,50,100]},
        {on: {occurs:[3,4,5], of:'Queen',   mode:'line'}, pay: [15,50,100]},
        {on: {occurs:[3,4,5], of:'King',   mode:'line'}, pay: [10,25,50]},
        {on: {occurs:[3,4,5], of:'Ace',   mode:'line'}, pay: [10,25,50]},
        {on: {occurs:[3,4,5], of:'Scatter',   mode:'scatter'}, pay: [5,25,100], trigger: 'freespins'}
    ]
});

You may ask yourself what happens when we run the game script above.. We run it and this is what happened: the engine generated reel strips automagically with a payback matching exactly what we asked, theoretical calculations were computed and a complete PAR SHEET(click to download) was generated, it all took three seconds... not bad.
And here is the output that was shown in the console of the IDE:


Generating reels with {"total":0.9121}

Reel strips: 
[
 ['Picture1', 'Picture1', 'Scatter', 'Jack', 'Wild', 'Jack', 'Queen', 'Queen', 'Jack', ...],
 ['Ace', 'Wild', 'Scatter', 'King', 'Ace', 'Picture1', 'Picture2', 'Nine', ...],
 ['Ten', 'Queen', 'Scatter', 'Picture3', 'Ten', 'Jack', 'Jack', 'Ten', ...],
 ['Ten', 'Queen', 'Scatter', 'Picture3', 'Ten', 'Jack', 'Jack', 'Ten', ...],
 ['Queen', 'Queen', 'Scatter', 'Queen', 'Jack', 'Picture2', 'Ten', 'Queen', ...]
]

Symbols frequencies on reels: 
{
 'Wild':     [2, 3, 1, 1, 1],
 'Picture1':      [3, 1, 3, 3, 3],
 'Picture2':        [1, 2, 3, 3, 3],
 'Picture3':  [5, 1, 5, 5, 5],
 'Nine':    [1, 5, 5, 5, 4],
 'Ten':       [1, 5, 5, 5, 5],
 'Jack':     [7, 1, 7, 7, 7],
 'Queen':     [7, 1, 7, 7, 7],
 'King':      [1, 7, 7, 7, 7],
 'Ace': [1, 7, 7, 7, 7],
 'Scatter':      [1, 1, 1, 1, 1]
}


Done! Executed in 3055ms

So what are the additional constraints you can provide in order to control the reel strips generation?
For each pay mode supported by the game you can set an upper limit or a lower limit to the corresponding theoretical payback percentage. You do so by injecting in the rtp object properties called paymodePaysMax and paymodePaysMin, where paymode is the paymode that you want to limit (scatter, line etc.). For instance you can have reel strips generated with a total payback percentage of 91.21% as before but this time set an additional constraint on the payback contribution of the scatter paymode, requiring that it does not go below 5%:
new Game({
    symbols: [
        {name: 'Wild', isWild:true}, 
        'Picture1', 'Picture2', 'Picture3', 'Nine', 'Ten',
        'Jack', 'Queen', 'King', 'Ace', 
        {name: 'Scatter', wildReplace: false} 
    ],
    rtp: {total: 0.9121, scatterPaysMin: 0.05},
    paytable: [        
        {on: {occurs:[2,3,4,5], of:'Wild',   mode:'line'}, pay: [5,50,500,5000]},
        {on: {occurs:[2,3,4,5], of:'Picture1',   mode:'line'}, pay: [3,40,200,1000]},
        {on: {occurs:[2,3,4,5], of:'Picture2',   mode:'line'}, pay: [2,30,150,500]},
        {on: {occurs:[2,3,4,5], of:'Picture3',   mode:'line'}, pay: [2,25,100,300]},
        {on: {occurs:[3,4,5], of:'Nine',   mode:'line'}, pay: [20,75,200]},
        {on: {occurs:[3,4,5], of:'Ten',   mode:'line'}, pay: [20,75,200]},
        {on: {occurs:[3,4,5], of:'Jack',   mode:'line'}, pay: [15,50,100]},
        {on: {occurs:[3,4,5], of:'Queen',   mode:'line'}, pay: [15,50,100]},
        {on: {occurs:[3,4,5], of:'King',   mode:'line'}, pay: [10,25,50]},
        {on: {occurs:[3,4,5], of:'Ace',   mode:'line'}, pay: [10,25,50]},
        {on: {occurs:[3,4,5], of:'Scatter',   mode:'scatter'}, pay: [5,25,100], trigger: 'freespins'}
    ]
});

With the above requirements we got reel strips generated paying as much as before, but this time the scatter contribution to the total payback of the game is 5,04%.
Despite having the same total payback, this slot game is very different from the previous one: in this game the bonus is triggered once every hundred games and the contribution to the total payback from the freespin bonus is nearly 12%. In the previous game (where we did not set any contraint on the scatter) the scatter contribution to the total payback was 1,95%, resulting on a freespin bonus being entered once every three hundred games and contributing to the total payback by 4,77% only.

Thus limiting payback of individual paymodes is a very powerful feature as it enables you to control the bonus hit frequency and the bonus payback, and this in turn dramatically affects the volatility of the game as well.

Reel strips generation with a custom function to control payback and bonus hit frequency

We have seen how it is possible to control the generation of reel strips by specifying a fixed value or an object for the rtp property. Higher control can be obtained by using a custom function as the value of rtp. When a function is provided it will be invoked by the engine during the reel strips generation and the reels will be generated so that the value returned by the function is minimized.

In the implementation of the function it is possible to represent multiple constraints that will be satisfied altogether (as much as possible!) by the generated reel strips.

The example below shows a game with a freespins and a pick-a-prize bonus with the reel strips being generated with the following constraints:
  • the overall payback of the game is 90%
  • the freespins bonus is triggered on average once every 100 spins
  • the pick-a-prize bonus is triggered on average oncde every 50 spins

new Game({
    symbols: [
        {name: 'WILD', isWild:true}, 
        'PIC1', 'PIC2', 'PIC3',
		'nine', 'ten', 'jack', 'queen', 'king', 'ace'
        {name: 'Scatter1', wildReplace: false},
        {name: 'Scatter2', wildReplace: false}
    ],
    rtp: function() {        
	var targetFsHitFreq = 0.01; //once every 100 spins
	var targetPapHitFreq = 0.02; //once every 50 spins
	var targetPayback = 0.900; //RTP
		
        var fsHitFreq = Math.abs(targetFsHitFreq - this.hits['scatter']['Scatter1'][3]/this.cycle);          
        var papHitFreq = Math.abs(targetPapHitFreq - this.hits['scatter']['Scatter2'][3]/this.cycle);           
        
	return (fsHitFreq > 0.01 ? 10*fsHitFreq : fsHitFreq) + 
			(papHitFreq > 0.01 ? 10*papHitFreq : papHitFreq) + 
			Math.abs(targetPayback - this.getTotalReturn());     
    },
    paytable: [        
		...
		...
        {on: {occurs:[3,4,5], of:'Scatter1',   mode:'scatter'}, pay: [0,0,0], trigger: 'freespins'},
        {on: {occurs:[3,4,5], of:'Scatter2',   mode:'scatter'}, pay: [0,0,0], trigger: 'pick_a_prize'}
    ],
    
    bonus: {
	freespins: {
		spin: [5, 10, 20]
	},
        pick_a_prize: {
		prize: [
			...
		]	
	}
	}
});	
The rtp function is called continuously during the reel strips generation. The value returned by the function is a result of the gap between the wanted bonus hit frequencies and the wanted payback. A ternary operator is used so that hit frequencies have a higher priority with respect to the payback contraint when the gap exceeds 1% (in this case the gap is multiplied by ten so that it drives the overall value returned by the function).

Game window

The game window determines the number of visible symbols on screen, which in turn depends on the number of reels and visible rows (visible cells on each reel after spinning).
Most times you don't need to specify the window of your slot game, the default value if suitable for most situations.
In order to define the game window provide a window property in your game configuration. The value must be an object that can contain two properties: reels for the number of reels in your game, rows for the number of visible rows.
Both properties can be omitted and will take the default value. When reels is omitted the engine will try to derive its value from the provided reels, if instead you are generating reels strips then you need to specify the value for this property. The default value for rows is 3.

The code below shows you how to define the game window of a 3x1 slot game:

new Game({
	window: {reels: 3, rows:1},
	...
});

Paylines

When running simulations of a slot game the required number of pay lines need to be provided.
This can be done by defining a property called paylines in the game configuration, as the following code snippet shows:

new Game({	
	...
	paylines: [		
		[0,0,0,0,0],
		[1,1,1,1,1],
		[2,2,2,2,2]		
	]
});
The value of paylines must be an array where each element is a pay line. Each pay line is defined as a list of row indexes, starting from the first visible row whose index is zero.

You normally don't need to specify pay lines unless you are working on a game with an exotic window or unless you need to run a simulation with a specific structure of the pay lines. That's because internally SLOT-IDE automatically provides pay lines for the most frequent game windows: 5x3, 5x4 and 3x3.

The internal pay lines are only used when no paylines property is provided in the game configuration.

Paytable

The paytable is defined as an array that lists the payouts of your game. By defining the payouts, you also specify how the symbols (or symbol combinations) pay.
By default SLOT-IDE supports the following paymodes: paylines, scatter pays, and scatters on adjacent reels.
Paymodes can be configured to respect the specific rules of your game in terms of alignment, whether or not coinciding hits are paid etc.

Each element of the paytable array can have the following properties:
  • on: object or string that specifies the winning combination(s) for the payout(s) defined in the element. The object can have the following properties:
    • occurs: array that lists the number of occurrences of the symbol specified in of needed to have a winning combination paying the corresponding value defined in pay. Properties occurs and pay must both be arrays having the same number of elements, except for the case when occurs is omitted. If occurs is omitted it defaults to a single value array corresponding to the number of reels in the game.
      For instance, providing the following element {on: {of: 'Queen', mode:'line'}, pay: 10} in the paytable of a 5 reels game means "pay 10 times the credits bet on the line when player has 5 occurrences of the Queen symbol"
    • of: string value indicating the symbol or the sequence of symbols that defines the paying combination(s) Its value can be:
      • the name of a symbol
      • a conditional symbol in the form Symbol1|Symbol2|Symbol3 (matching ANY of the pipe-separated list of symbols provided, e.g. BAR1|BAR2|BAR3 means any BAR symbol)
      • or a sequence of symbols (line paymode only) in the form Symbol1,Symbol2,Symbol3. This last format can be used to define a combination that matches a specific sequence of symbols on the line and it's normally useful for 3 reels slot. When providing a sequence the values in the occurs property specify the number of symbols in the sequence that have been obtained on the line, reading the sequence from left to right.
        For instance by providing the following element in the paytable:

            {on: {occurs:[4,5], of:'Nine,Ten,Jack,Queen,King', mode: 'line'}, pay: [20, 50]}

        means "pay 20 times the credits bet on the line when player has the sequence Nine, Ten, Jack and Queen" and "pay 50 times the credits bet on the line when player has the sequence Nine, Ten, Jack, Queen and King"
    • mode: name of the paymode for the combination(s) defined in the element. The value can be one of line (paylines), scatter (scatter symbols), consecutive (scatter paying on adjacent reels), line_scatter (scattered symbol on an active payline). Defaults to line
    when providing a string for the on property instead of an object the engine creates an object and uses it as the value for the property of. The remaining properties (occurs and mode) take their default values.
  • pay: number or array that provides the payout(s) for the combination(s) defined in element
  • trigger: name of the bonus triggered by the combination(s) defined in element. The name of the bonus must match one of the properties specified in the bonus object

Paymodes

SLOT-IDE supports the following pay modes:
  • line: symbols aligned on an active payline. The win amount equals the value pecified in the paytable multiplied by the credits bet-per-line. See next section to know how to configure the alignment.
  • scatter: symbols scattered on the visible matrix. The win amount equals the value specified in the paytable multiplied by the total credits bet (number of selected paylines X credits bet-per-line)
  • consecutive: symbols scattered on consecutive reels. See next section to know how to configure the alignment.
  • line_scatter: symbols scattered on an active payline. It is important to remember that line_scatter wins do not interfer with line wins. That is, plain payline wins are evaluated by respecting the only-highest-win-on-an-active-payline-is-paid rule, while line_scatter wins evaluated regardless of plain payline wins and do not take this rule into account.

Paymodes configuration

Paymodes line and consecutive can be configured for what concerns alignment and whether or not coinciding hits are paid.
This is done by providing properties called paymodeMode in the game configuration, where paymode must be one of line and consecutive. The value can be either a string specifying the alignment, or an object with two properties: align, coinciding.
If no paymodeMode property is specified in the game configuration the default mode is applied to the corresponding paymode.
The value for property coinciding is boolean and defaults to false: meaning that coinciding wins aren't paid.

For line paymode the value of align property must be one of:
  • left: symbols on consecutive reels from left to right. This is the default value
  • right: symbols on consecutive reels from right to left
  • left_right: symbols on consecutive reels from left to right and right to left. For this alignment the value of coinciding property determines whether in the case of coinciding wins on the same payline (one from left and one from right) both wins are paid or only the highest one
For consecutive paymode the value of align property must be one of:
  • left: scatter symbols on consecutive reels from left to right. This is the default value
  • right: scatter symbols on consecutive reels from right to left
  • left_right: scatter symbols on consecutive reels from left to right and right to left. For this alignment the value of coinciding property determines whether in the case of coinciding wins in the same window (one from left and one from right) both wins are paid or only the highest one
  • any: symbols on consecutive reels with no alignment. The value of coinciding property determines whether in the case of coinciding wins in the same window all wins are paid or only the highest one (for instance in a 7 reels game one could have a scatter on the first two reels, and then a scatter on the fourth and fifth reels, thus paying twice the combinations for two occurrences if coinciding wins are paid)
The code below shows how you can define a slot game with paylines paying from left to right and right to left with coinciding wins paid:

new Game({
	...
	lineMode: {
		align: "left_right",
		coinciding: true
	}
	...
});

Win ways

SLOT-IDE now also supports slots where wins are paid on win ways. Depending on the visible rows you have in your slots there will be 243 or 1024 win ways.
Currently support for win ways is limited to betting on all reels (all available win ways selected). To define a slot game that pays on win ways all you need to do is specify the overall cost for betting on all reels (that means betting one credit on all available win ways). You do this by using an attribute called reelsCost, as shown here below:

new Game({
    window: {reels:5, rows: 3},
    reelsCost: 50, 
    ...
});

Then in your paytable all the symbols paying on win ways can be specified with line paymode as for regular paylines.
The example above defines a 243 win ways slot. In this case the minimum bet is 50 credits (50 credits are needed to bet one credit on each of the 243 win ways).

Bonuses

SLOT-IDE virtually supports any kind of bonus. In your game configuration you can specify one or more bonuses that will be triggered either by one or more of the paying combinations (the ones listed in the paytable) or with a custom trigger.
The built-in bonus support of SLOT-IDE splits the various bonus types into two main categories: freespin-like bonuses and pick-a-price bonuses. Both categories include a vast number of bonus types, for instance all kind of freespin bonuses and dynamic bonuses fall in the first category, while wheels, pick-a-price and trails fall in the second one.

Depending on the rules of your game, bonuses can be re-triggered (triggered again while already playing the bonus) and through the configuration you can easily represent the situation where while already in a bonus you can trigger other bonuses (different than the one you are playing). For instance in one of your game you could define a freespin bonus that while it's been played can also trigger a pick-a-prize bonus.

Any property you use to describe the rules of a bonus is dynamic, this means that its value can either be specified as a constant or as a function that will be called every time the value is needed. This enables you to easily implement dynamic bonuses with rules that introduce a dependency on the state of the game (for instance you can award 10 spins when the bonus is triggered from the base game and award 3 spins only when the bonus is triggered again during free spins).

You declare the bonuses of your game in an object called bonus. Each property of the bonus object defines an individual bonus. The name of the property is the bonus name that you use to specify the triggers for the bonus in the paytable. The example below shows a game that defines two bonuses triggered by two different scatters:

new Game({
    ...
    ...,	
    paytable: [        
	...
	{on: {occurs:[2,3,4,5], of:'Scatter1',   mode:'scatter'}, pay: [2,5,25,100], trigger: 'superspins'},
	{on: {occurs:[2,3,4,5], of:'Scatter2',   mode:'scatter'}, pay: [2,5,25,100], trigger: 'pick-a-prize'}
    ],
    bonus: {
	superspins: {
		...
		...		
	},
	'pick-a-prize': {
		...	
		...
	}
    }	
});
You may be wondering how can you define the rules for your bonus(es) and how is it possible to represent different bonus types like freespins, wheels or pick-a-prize. You do this by using specific properties in your bonus object(s).
Before going through the list of properties that you can use, let's see how to implement a simple freespin bonus:

new Game({
    ...
    ...,	
    paytable: [        
	...
	{on: {occurs:[2,3,4,5], of:'Scatter',   mode:'scatter'}, pay: [2,5,25,100], trigger: 'freespins'}
    ],
    bonus: {
	freespins: {
		spins: [0, 5, 10, 15]
	}
    }	
});
The example above defines a game with a freespin bonus triggered by the scatter. The spin property defines the number of freespins awarded when the bonus is triggered. Because an array is given as its value then the elements in the array represent the number spins awarded for each scatter combination that triggers the bonus (0 spins are awarded for 2 scatters, 5 spins for 3 scatters, 10 spins for 4 scatters and 15 spins for five scatters). The spins property doesn't necessarily specify the number of freespins, it has a wider meaning as it represents more generically the number of times that the bonus game is played. For freespins bonuses playing the bonus means spinning the reels, but for other kind of bonuses the actual bonus game is not necessarily a reel game. To define non-freespin bonuses you can use the prize property, this enables you to represent all bonuses that ramdomly award prizes to the player, regardless of the way the bonus game is presented to the player (this includes trails, wheels, pick a prize etc.). Here is an example:

new Game({
    ...
    ...,	
    paytable: [        
	...
	{on: {occurs:[2,3,4,5], of:'Scatter',   mode:'scatter'}, pay: [2,5,25,100], trigger: 'wheel'}
    ],
    bonus: {
	wheel: {
		spin: [0, 2],
		prize: [
			{prob: 0.5, prize: 5},
			{prob: 0.35, prize: 10},
			{prob: 0.10, prize: 20},
			{prob: 0.05, prize: 50}
		]
	}
    }	
});
The example above defines a wheel bonus. Two spins of the wheel are awarded if the bonus is triggered with three or more scatters (notice the leading zero in the spin array that prevents the bonus from being triggered with two scatters). Each time the wheel is spun a prize is chosen randomically according to the specified probability table (for instance the player has 5% probability to win a prize of 50 times the total bet).
To summarize, if you do not specify the prize property then SLOT-IDE assumes that you are defining a freespin bonus (the sections that follow will describe how to define and control the reel game that is played in freespin bonuses). If instead you use the prize property then each time the bonus is played a prize is awarded according to the value provided for the prize property.

You may at this point wonder two things:
  1. how is it possible to define a wheel bonus like the one above that besides awarding a prize can also award additional spins of the wheel?
  2. how is it possible to define a freespin bonus that can also award a mystery prize after the reels are spun?
a. can simply be done by entering in the prize table items with a spins property. Each item can award a prize, a number of spins or both.
To show this let's modify the wheel bonus of the previous example so that when the last prize is picked the player will not only win x50 but also two additional spins of the wheel:

new Game({
    ...
    ...,	
    paytable: [        
	...
	{on: {occurs:[2,3,4,5], of:'Scatter',   mode:'scatter'}, pay: [2,5,25,100], trigger: 'wheel'}
    ],
    bonus: {
	wheel: {
		spin: [0, 2],
		prize: [
			{prob: 0.5, prize: 5},
			{prob: 0.35, prize: 10},
			{prob: 0.10, prize: 20},
			{prob: 0.05, prize: 50, spins: 2}
		]
	}
    }	
});
b. can be done by using the property additionalPrize to define the mystery prizes. The value of this property has the same format as the prize property, but when you use additionalPrize the bonus is still a freespin bonus and the prize is awarded just after the spin is played (the sections that follow will describe how to award the mystery prize conditionally, this will allow you among the other things to define a freespin bonus where the mystery prize is awarded only at the end of the bonus just after the last spin is played). The example that follows defines a freespin bonus where a myster prize is awarded each time a freespin is played, and the prize is chosen randomly to be twice the bet 90% of the times, five times the bet 5% of the times and an additional freespin 5% of the times:

new Game({
    ...
    ...,	
    paytable: [        
	...
	{on: {occurs:[2,3,4,5], of:'Scatter',   mode:'scatter'}, pay: [2,5,25,100], trigger: 'freespins'}
    ],
    bonus: {
	freespins: {
		spin: 5,
		additionalPrize: [
			{prob: 0.90, prize: 2},
			{prob: 0.05, prize: 5},			
			{prob: 0.05, spins: 1}
		]		
	}
    }	
});
Now that we have seen how to cover the simplest kind of bonuses let's summarize the properties that can be used:
  • spins: defines the number of free games awarded to be played in the bonus.
    The value must either be a number, or an array that provides the spins for each combination defined by the trigger. Each element in the array specifies the number of spins awarded for the corresponding triggering combination in the paytable, therefore the elements of the spins array are related to the ones of the occurs array of the bonus trigger.
    By entering a value of zero in the array you prevent the corresponding number of occurrences to trigger the bonus.
    If the size of the spins array is lower than the size of the occurs array then the last element defines the spins awarded for all other triggering combinations.
    Whether spins is provided as a single value or as an array, the actual number of spins can be expressed either as an integer or as a list of objects carrying probability-spins pairs (in the case of the array each element is itself an array of objects). This enables you to represent rules of the form "win 30 spins 25% of the times, win 10 spins 75% of the times". You might think that from a theoretical point of view such situation might as well be described with a unique number of spins equal to the weighted average of the probabilities-spins pairs, but this would not work for two reasons:
    • in order to properly evaluate the standard deviation of the game during simulations every feature or rule that can influence the spread of the payout distribution or that is subject to statistical fluctuations should be represented in a way that its probabilistic nature is respected
    • by entering the list of probability-spins pairs the same definition of the bonus is correct for both theoretical calculations and for running simulations or playing the actual game
    • the slot engine internally needs to work with integer values for the number of spins to be played
  • maxSpins: enables you to set a limit on the overall number of spins that will be played from the moment the bonus is triggered
  • maxRetriggers: limits the number of times the bonus can be retriggered (setting the value to zero prevents the bonus from ever being triggered again during freespins)
  • enterFromBonus: this property is used to control the game flow when multiple bonuses are triggered. This happens when either a bonus is triggered again while it is being played or when a game features multiple bonuses and bonusB is triggered while playing bonusA. If the value for enterFromBonus is set to true or to the name of the bonus that is currently being played then when the bonus is triggered the bonus game will start and at the end of it the player will continue to play the previous bonus. In all other cases the newly triggered bonus will be played when all other active bonuses are over. The default value for enterFromBonus is false.
  • multiplier: multiplier to be applied to the wins obtained in freespins. The value can either be a number representing the fixed multiplier or an array of objects containing probability/multiplier values (see example at the end of this section)
  • multiplierScope: this property lets you specify the life time for the value of the multiplier. When no multiplierScope is provided, the value of the multiplier is obtained at the beginning of the bonus game and the same value is used until the bonus is over. If multiplierScope is set to spin then the value of the multiplier is queried at the beginning of each spin in the bonus. This can be used when a dynamic value for the multiplier is specified.
  • trigger: enables you to define a custom bonus trigger (see next sections)
  • additionalPrize: additional prize that is awarded each time a freespin is played. The value can either be a number representing the fixed prize that is to be awarded or an array of objects containing probability/prize values for mystery prizes
  • prize: prize to award each time the bonus is played. You use this property to define non-freespin bonuses like wheels, trails or pick-a-prize bonuses. The value must be in the same format as for additionalPrizeproperty
The following example shows a game with a freespins bonus triggered by the scatter symbol and the following rules: when the player gets three scatters ten spins in the bonus are awarded, when the players gets four or five scatters a mystery value for the number of spins is awarded according to the table provided (twenty spins with 60% probability, thirty spins with 30% probability and fifty spins with 10% probability). Because of the leading zero in the spins array no freespins are awarded when two scatters only are obtained. While in the bonus all wins are multiplied by 2x, after playing each spin five additional credits are awarded, the bonus can be retriggered three times at most, the total number of spins that can be played after entering the bonus is limited to a hundred.

new Game({
    ...
    ...,	
    paytable: [        
	...
	{on: {occurs:[2,3,4,5], of:'Scatter',   mode:'scatter'}, pay: [2,5,25,100], trigger: 'superspins'}
    ],
    bonus: {
	superspins: {
		maxSpins: 100,
		maxRetriggers: 3,
		spins: [
			0,  //don't trigger the bonus with 2 scatters only
			10,
			[
				{spins: 20, prob: 0.6},
				{spins: 30, prob: 0.3},
				{spins: 50, prob: 0.1}					
			]
		],
		multiplier: 2,
		additionalPrize: 5
	}
    }	
});
The following example shows a game with a freespins bonus with a mystery multiplier applied to all wins whose value is chosen randomly when the bonus is triggered:

new Game({
    ...
    ...,	
    paytable: [        
	...
	{on: {occurs:[2,3,4,5], of:'Scatter',   mode:'scatter'}, pay: [2,5,25,100], trigger: 'superspins'}
    ],
    bonus: {
	superspins: {
		spins: 10,
		multiplier: [
			{prob: 0.6, multiplier: 2},
			{prob: 0.3, multiplier: 5},
			{prob: 0.1, multiplier: 10}
		]
	}
    }	
});
So far we have only covered the configuration of simple bonuses where each property carries a static value. Bonuses can be much more complex, there can be rules that require the properties used to describe the bonus to be dynamic (for instance the prize property of a wheel bonus could define a wheel for the first spin and a different wheel for subsequent spins) or there can be freespin bonuses where the bonus is played on a set of reels different than the base game or on a configuration of the reel strips that evolves spin after spin according to specific rules (this is the case for a freespin bonus with an expanding wild).

The next two sections explain how to implement rules requiring dynamic properties and how to define the reel strips used in freespin bonuses and control how the reels evolve according to the rules of the bonus.

Bonus rules requiring dynamic properties

In order to describe the rules of the bonus it is very frequent that bonus properties cannot be represented by a constant value.
SLOT-IDE makes it easy to support these situations: the value of any bonus property listed in the previous section can be defined as an anonymous function rather then a constant value (if you aren't familiar with anonymous functions all you need to know if that they don't have a name and they are assigned to a variable so that they can be invoked using the variable's name). The function will be invoked by the engine anytime that the value of the corresponding property is needed. Obviously the value returned by the function must be in the same format as it was described for the specific property that the function is attached to.

Rules requiring a property of the bonus to be dynamic normally need to relate the value of the property to a specific condition, therefore in order to implement such rules one often needs to access contextual information of the bonus game that is currently being played. To make this possible, SLOT-IDE exploits the great flexibility of the javascript language: besides supporting anonymous functions, javascript also allows you to assign, at invoke time, the context to the function being invoked. What this means in practice is that each time you define a function for a dynamic property, in the body of the function you can use an object called this that contains in its properties the context of the bonus game that is being played.

What follows is the list of properties that are available in your functions within this:
  • game: a reference to the game object
  • bonus: a reference to the object representing the bonus that was initially triggered (freespin bonuses can trigger other bonuses while the freespins are played, bonus always refers to the bonus that was triggered initially from the base game)
  • triggers: number of times the bonus is triggered. Be aware that depending on which property your function is attached to, it is possible that when the function is invoked the value of this property is still zero, this is what happens when the bonus is about to bet triggered from the base game
  • played: number of spins played since the bonus was triggered. As for the triggers property, the value of played is zero just after the bonus is triggered from the base game until the first spin is played
  • triggering: this property is only defined when a bonus is being triggered. The triggering of a bonus can occur from the base game or when while playing freespins. The value of triggering is an object with two properties: bonus carrying the name of the bonus being triggered and trigger. The latter is an object containing the paytable element that is currently triggering the bonus. The occurs though is not the complete already that was specified in the paytable but contains only the number of occurrences of the triggering combination (if the bonus is triggered by four scatters and in the paytable the element corresponding to scatter win has occurs: [2,3,4,5] then the value of occurs in trigger will be set to [4] only).
  • playing: name of the bonus currently being played. At the time the bonus is triggered from the base game this property is not defined because no spin is being played yet. For games featuring two or more freespins bonuses that can (re)trigger each other, the value of playing can be different from the name of the bonus that was initially triggered from the base game.
  • state: name of the current reel strips state that is being played in the bonus game (see next section)
  • states: object containing all the reel strips states defined so far (see next section)
Let's demonstrate how to use the context of the bonus game in dynamic properties with an example. The code snippet below shows a game with a freespins bonus that is triggered by the scatter and implements the following rules:
  • three or more scatters trigger the bonus and ten free spins are awarded
  • the bonus can be re-triggered one time only and five free spins are awarded when it is triggered the second time
  • while playing each free spin an additional prize of three credits is awarded only if the bonus isn't triggered again
new Game({
    ...
    ...,	
    paytable: [        
	...
	{on: {occurs:[3,4,5], of:'Scatter',   mode:'scatter'}, pay: [5,25,100], trigger: 'superspins'}
    ],
    bonus: {
	superspins: {
		maxRetriggers: 1,
		spins: function() { return this.played == 0 ? 10 : 5; },
		additionalPrize: function() { return this.triggering ? 0 : 3;}
	}
    }	
});
The above example shows a good mixture of static and dynamic bonus properties and it also demonstrates how complex rules can be implemented with just one line of code! For those unfamiliar with anonymous functions and ternary operators, the spins property can be read as "when no spin has been played yet (initial triggering the bonus from the base game) award ten free spins, all other times (triggering the bonus while playing freespins) award five".

Defining the reel game in freespin bonuses and implementing rules requiring the game to evolve

So far it has been explained how to represent bonuses using properties and how to implement rules that require the parameters of the bonus to change based on some conditions. For freespin bonuses we have also assumed that the freespins are played on a reel game that is exact clone of the base game (same reels, same symbols etc.). In a large number of freespin bonuses though, spins are played either on a different set of reel bands (often having a higher payback in order to make the bonus more attractive) or on a reel game that features additional symbols or that can evolve spin after spin. The latter is the case of bonuses with an expanding wild that sticks on the reels where it appears, or even bonuses with simple rules like "after each spin in the bonus a wild is added to each reel".
SLOT-IDE enables you to easily implement such bonuses as well: in the bonus configuration it is possible to control the state of a bonus and its evolution by taking advantage of three additional properties.
The state of a bonus represents the specific reel game that is being played in the current spin. Bonus states are configuration objects following the same syntax you use to describe the base game and are identified by a name. By default every bonus is played in a state called main which is a clone of the base game, this is the reason why in all previous examples the bonus game was never defined.

The properties that you can use to define and control the state of the bonus are:
  • enterState: defines the name of the state that is played when the bonus is triggered initially. The value can either be a string or a list of state/probability pairs. In the latter case the list is an array whose elements are objects with two properties: state for the name of the state and prob for the probability corresponding to the situation where one starts to play the bonus in that specific state.
    Alternativaly the value of enterState can also be a function that returns a string or an array in the same format. Defaults to "main"
  • stateProvider: this property is meant to define the states needed by the bonus during its life cycle. Anytime a state is needed for the first time the engine tries to obtain it from the value of stateProvider. The value can either be an object or a function. Use an object to provide in one goal all the states that will ever be needed: the properties of the object are names of the states, while the values are the configuration objects describing the corresponding states. Use an anonymous function to provide states dynamically: the function will be invoked as soon as a state is needed and it is meant to return a single object representing the configuration of the needed state (in this case in order to know what state needs to be returned one can use the state property of the context object).
    To specify the value of each state, you can provide a configuration object as described or you can also provide a superposition of multiple states. The latter is useful when from the rules of the bonus it follows that each freespin can be played on a number of possible states that are chosen with a fixed probability table. In this case you can base the bonus on a single virtual state that is in turn a superposition of states and then return its value in stateProvider as an array of state/probability objects (where the value of the state property is a configuration object describing the individual state and the prob property is the probability of playing in that state). The next section shows an example of states superposition.
  • stateTransitions: this property is used for connecting states. By providing the transition probabilities as the value of the property you control to which states each state can evolve spin after spin
    For instance if the bonus initial state is main then you can say that after the freespin is played the state can evolve to state1 20% of the times and to state2 50% of the times or remain in state main the remaining 30% of the times.
    After playing a spin the engine uses the value of stateTransitions to know to which states the current state can evolve. Therefore stateTransitions has to provide a list of state/probability pairs, this list must be an array containing objects with two properties: state carrying the name of the destination state and prob for the corresponding transition probability (that is the theoretical probability of going from the current state to the destination state). As for stateProvider, the actual value of stateTransitions can either be an anonymous function or an object. When you provide a function, the function is meant to return the list of state transitions for the current state _ (state property of the context object) as an array. When you provide an object you specify a static mapping between each state and the corresponding list of transitions, therefore the properties of the object are the name of the source states, and the values can either be an array listing the transitions for the corresponding state or an anonymous function returning the list as an array.

    Obviously state transitions are not the only possible evolutions that can happen during the life cycle of a bonus phase. After each spin the state also evolves to a situation where the number of accumulated spins is decremented by one (the spin that was just played) and incremented by the number of spins won by any bonus trigger that occurred during the spin, if any. Depending on the nature of the state transition that is being represented and the underlying game rule governing it, it is possible that the event of (re)triggering a bonus is related to the event of evolving from one state to another. In this case the functions in stateTransitions are in charge of computing and returning the conditional probability of going from state1 to state2 given that a bonus is being triggered, or given that no bonus was triggered during the spin.
    This can easily be done by reading the value of the triggering property in the context object to know whether or not a bonus was triggered during the spin.
The example below shows a game with a freespin bonus based on the following rules:
  • the bonus can be re-triggered twice
  • six free spins are awarded when triggering the bonus from the base game and three free spins are awarded when re-triggering it
  • after each spin played in the bonus a wild symbol is added to all reels
new Game({
    symbols: [
        {name: 'Wild', isWild:true}, 
        'Picture1', 'Picture2', 'Picture3', 'Nine', 'Ten',
        'Jack', 'Queen', 'King', 'Ace', 
        {name: 'Scatter', wildReplace: false}
    ],	
    ...,
    bonus: {
        freespins: {			
            spins: function () { return this.triggers == 0 ? 6 : 3; },
            maxRetriggers: 2,
            enterState: 'spin:0',
            stateTransitions: function()
            {
                var spins = parseInt(this.state.split(":")[1]); 
                return [{state: 'spin:'+(spins+1), prob: 1.0}];
            },            
            stateProvider: function ()
            {
                var spins = parseInt(this.state.split(":")[1]);                
                var newState = this.game.clone();    
                
                for (var i=0; i < spins; i++)
                {
                    for (var reel=0; reel < 5; reel++) 
                    {
                        newState.reels[reel].push('Wild');
                    }
                }                
                return newState;                            
            }
        }
    }
});

Running theoretical calculations of the game script above produces this PAR SHEET (click to download).

Here comes an explanation of how the bonus was implemented:
The spins property is dynamic, a ternary operator is used to return the proper number of spins based on whether or not this is the initial trigger.
The property enterState is set to a state called spin:0, this is the state that is played initially, just after the bonus is triggered (first spin played). All other state names are in the form of spin:N where N represents the number of wild symbols added to the reels.
The property stateTransitions is used to connect states. For each state the only possible transition is to go to the next one, thus state:N can only go to state:N+1 100% of the times. The function provided reads the name of the current state from the context object, extracts the number of wilds added in the state, increments this number by one, and uses it to build up the name of destination state.
The property stateTransitions is used to create the required state. Each time a state object is needed, the function gets called and this is what it does: reads the name of the current state from the context object and extracts the number of wilds from it. Then it creates the corresponding state by cloning the configuration of the base game and adding to its reels as many wilds as required.

Playing a superposition of states in the bonus

When your bonus game can be played on a number of different states that are chosen with a fixed probability table it can be useful to describe your bonus with a virtual state that is a superposition of the possible states. Depending on the bonus rules the state can be chosen only once when the bonus is triggered from the base game or anytime a spin is played. In the first case there are two ways to describe the bonus: either by using enterState to return the probability of entering the bonus in each possible state or defining a unique virtual state and then using stateProvider to return its value as a superposition of states.
Both ways will be shown, it is worth saying that when possible the second way is more convenient from a computational point of view (a single virtual state is evolved and theoretical calculations are based on the weighted average of the states rather than the evolution of all possible initial states). This should be considered especially when the number of possible states is high (over ten).

Let's use an example game to show both ways. We consider a freespin bonus where the Queen symbol or the Jack symbol become an additional wild in the bonus. The choice of which symbol becomes wild depends on a fixed probability table (80% of the times Queen is chosen and 20% of the times Jack is chosen). Thus the bonus can be described by two states and enterState can be used to define how to choose the state when the bonus is triggered:
new Game({
    symbols: [
        {name: 'Wild', isWild:true}, 
        'Picture1', 'Picture2', 'Picture3', 'Nine', 'Ten',
        'Jack', 'Queen', 'King', 'Ace', 
        {name: 'Scatter', wildReplace: false}
    ],	
    ...,
    bonus: {
        freespins: {			
            spins: 10,
            enterState: [
		{state: 'JackIsWild', prob: 0.2}, 
		{state: 'QueenIsWild', prob: 0.8}
			],	
            stateProvider: function ()
            {
		var wildSymIndex = this.state == 'JackIsWild' ? 6 : 7;
		var wildSymName = this.state == 'JackIsWild' ? 'Jack' : 'Queen';
                var newState = this.game.clone();    
				
                newState.symbols[wildSymIndex] = {name: wildSymName, isWild: true};
                return newState;                            
            }
        }
    }
});

Let's now describe the same bonus using the second way. This time we use enterState just to label the unique virtual state and then we use stateProvider to return its value as a superposition of the two states.
new Game({
    symbols: [
        {name: 'Wild', isWild:true}, 
        'Picture1', 'Picture2', 'Picture3', 'Nine', 'Ten',
        'Jack', 'Queen', 'King', 'Ace', 
        {name: 'Scatter', wildReplace: false}
    ],	
    ...,
    bonus: {
        freespins: {			
            spins: 10,
            enterState: 'virtual',
            stateProvider: function ()
            {
		var stateQueen = this.game.clone();    
                stateQueen.symbols[7] = {name: 'Queen', isWild: true};

		var stateJack = this.game.clone();    
		stateJack.symbols[7] = {name: 'Jack', isWild: true};

                return [
			{prob: 0.2, state: stateJack},
			{prob: 0.8, state: stateQueen}					
		];                            
            }
        }
    }
});

Chosing randomly the bonus to trigger

We have seen that each win in the paytable can also trigger a bonus. The bonus triggered when the winning combination get hits is defined by the trigger attribute. In games that feature multiple bonuses it is also possible to pick up one of the bonuses randomly and then trigger it. This is done by using an array of bonus/probability pairs as the value of the trigger attribute.

The following example shows a game with a freespins and pick-a-prize bonus both triggered by scatter wins. Once a scatter win is hit the freespins bonus is triggered on average 40% of the times while the pick-a-prize bonus is triggered on average 60% of the times.
new Game({
    symbols: [
        {name: 'Wild', isWild:true}, 
        'Picture1', 'Picture2', 'Picture3', 'Nine', 'Ten',
        'Jack', 'Queen', 'King', 'Ace', 
        {name: 'Scatter', wildReplace: false}		
    ],    
    reelFreqs: {                                
        'Wild':   [1,1,1,1,1],
        'Picture1':  [2,3,2,2,3],
        ...
    },
    paytable: [        
        ...,
        {on: {occurs:[3,4,5], of:'Scatter',   mode:'scatter'}, pay: [5,25,100], trigger: [
			{bonus: 'freespins', prob: 0.4}, 
			{bonus: 'wheel', prob: 0.6}
		]}
    ],
    bonus: {
        freespins: {
            spins: 10, 
            multiplier: 3,
            stateProvider: function() {
                var s = this.game.clone();
                delete s.paytable[s.paytable.length-1].trigger;
                return s;   
            }
    	},
        wheel: {
            prize: [
                {prize: 2, prob: 0.35},
				{prize: 5, prob: 0.45},
                {prize: 10, prob: 0.15},
                {prize: 15, prob: 0.05}				
            ]
        }
    }
});

Defining custom bonus triggers

Sometimes in order to represent complex situations that involve the way freespins bonus are triggered, it can be useful to provide in the bonus configuration a custom trigger. Plain triggers are the ones that you define in the paytable, where you connect one or more paying combinations to a bonus. Therefore by default, only winning combinations can trigger a bonus. What's even more important is that for the plain triggers to generate valid results the corresponding winning combinations have to be totally indipendent, meaning that there cannot be coinciding wins triggering the same bonus.
For the majority of games this is not a limitation, but what if you have a bonus that gets retriggered based on a fixed probability? Or what if you want to implement a play-as-long-as-you-win freespins bonus where you win another free spin if you get any win in the current spin? In the latter case the probability of triggering the bonus is the probability of getting any win, which because of coinciding wins is lower the the sum of the probabilities of each win.

Therefore SLOT-IDE makes it possible to provide custom triggers that are defined by a fixed probability or by a function that returns the triggering probability dynamically.
In order to define a custom trigger provide a property called trigger in the bonus configuration object. If you use a function you can take advantage of the context object and return a probability conditionally. Custom triggers can be used together with plain triggers, this allows you to trigger a bonus with a win from the paytable and to retrigger it with a fixed probability, as shown in the example below:
new Game({
    symbols: [
        {name: 'Wild', isWild:true}, 
        'Picture1', 'Picture2', 'Picture3', 'Nine', 'Ten',
        'Jack', 'Queen', 'King', 'Ace', 
        {name: 'Scatter', wildReplace: false}
    ],    
    reelFreqs: {                                
        'Wild':   [1,1,1,1,1],
        'Picture1':  [2,3,2,2,3],
        ...
    },
    paytable: [        
        ...
        {on: {occurs:[3,4,5], of:'Scatter',   mode:'scatter'}, pay: [5,25,100], trigger: 'freespins'}
    ],
    bonus: {
        freespins: {
            spins: 10, 
            multiplier: 3,
            stateProvider: function() {
                var s = this.game.clone();
                delete s.paytable[s.paytable.length-1].trigger;
                return s;   
            }, 
            trigger: function() { return this.triggers == 0 ? 0 : 0.006; }
    	}
    }
});

Here is what the above game script does:
the bonus is initially triggered by three, four or five scatters wins. The bonus configuration provides the main state (stateProvider is called only once in order to provide the default state). This state is created as a clone of the base game, but without the scatter trigger (trigger property is deleted from the last element of the paytable), so the bonus cannot be retriggered by scatter wins.
Then a custom trigger is provided which only effects the retriggering of the bonus (the function returns zero probability when the bonus hasn't been triggered already). The bonus is retriggered with a fixed probability of 0.6%.

Multiple bonuses and mutual triggering

We close this section with an example game that features two bonuses: a freespin bonus and a wheel. Depending on the rules of the game it can be possible to enter the wheel bonus from the base game and also from the freespins. Let's describe the situation where the wheel bonus can only be entered from the base game and the freespins are played on the same reel game as the base game: in stateProvider we use a function that defines the bonus state as a clone of the base game and then removes the trigger property from the last element of the paytable array (to prevent the freespins from triggering the wheel bonus).
new Game({
    symbols: [
        {name: 'Wild', isWild:true}, 
        'Picture1', 'Picture2', 'Picture3', 'Nine', 'Ten',
        'Jack', 'Queen', 'King', 'Ace', 
        {name: 'Scatter1', wildReplace: false},
        {name: 'Scatter2', wildReplace: false}		
    ],    
    reelFreqs: {                                
        'Wild':   [1,1,1,1,1],
        'Picture1':  [2,3,2,2,3],
        ...
    },
    paytable: [        
        ...,
        {on: {occurs:[3,4,5], of:'Scatter1',   mode:'scatter'}, pay: [5,20,50], trigger: 'freespins'}
        {on: {occurs:[3,4,5], of:'Scatter2',   mode:'scatter'}, pay: [5,25,100], trigger: 'wheel'}
    ],
    bonus: {
        freespins: {
            spins: 10, 
            multiplier: 3,
			enterState: 'freespins',
            stateProvider: function() {
                var s = this.game.clone();
                delete s.paytable[s.paytable.length-1].trigger;
                return s;   
            }
    	},
        wheel: {
            prize: [
                {prize: 2, prob: 0.35},
		{prize: 5, prob: 0.45},
                {prize: 10, prob: 0.15},
                {prize: 15, prob: 0.05}				
            ]
        }
    }
});