Big Draco's FP guide
Future Pinball
Scripting
Welcome to Code Corner!

This area of the website will develop so check back often.

At the moment, the following snippets may be of use...

 
 

The Dim Statement - Syntax  Dim variablename

The Dim statement (short for dimension) is used to declare or tell the program that you want to create a variable. A variable is a place holder that points to an area of memory that the program can use to store a value. Rather than use a complicated memory address (which changes each time the program is run), this variable name can be used instead.

It is important that the program allocates enough memory to store values which is why we need to tell the computer that we want it to allocate space to store a value. In compiled programs (.exe files) it is usual to define not only the name of the variable but also its data type (character, numeric etc) but also how big it is. This is not necessary in VB Script (the language Future Pinball (FP) uses) as the script is interpreted. That means it executes statements 'on the fly' (which is why you do not always get a script error when you start a table up, but can occur when a certain piece of code is run).

Example:

       Dim myvariable

This tells the program that we want an area reserved for a value and will reference it within the program as 'myvariable' (Note the the script language is not case sensitive, so MyVariable is the same as myvariable.

In programming it is common to talk about variables and constants but what is the difference? In short, variables do and constants don't! That means that during the execution of a program, a variable's value may change (vary) whilst a constant remains the same value throughout - it never changes. There is no difference in definition of a variable or a constant - which is which is entirely up to you although you can use the Const declaration for constants.

To top

Local and Global Variables - an explanation

This is an area that can often confuse new programmers and getting this wrong can cause some weird results! I use the terms 'Local' and 'Global' but they can also be known as 'public' and 'private' depending on the language being written.

Local Variables (Private)

These are variables that have been defined within a single subroutine. They are only available to that routine. For example, take the following piece of code that you might find in an FP table script...

Sub bumper1_hit()
Dim bumperhitcount

    bumperhitcount = bumperhitcount + 1
    Addscore(100)

End Sub

Sub bumper2_hit()
Dim bumperhitcount

    bumperhitcount = bumperhitcount + 1
    Addscore(100)

End Sub

Note that in each of these subroutines there is a variable that has been defined called bumperhitcount. As this variable has been defined within each subroutine it would be classed as a local or private variable. That means that it is only available to that subroutine.

If the player hit bumper 1 two times and bumper 2 three times, each variable would hold '2' and '3' respectively. It would not hold '5' because these local variables are separate from each other. If you wanted a variable to hold the total  number of times a bumper has been hit, you would need to Dim a global or public variable.

Global Variables (Public)

These variables are defined outside  the subroutine (and within an FP script, the place to do this is immediately beneath the comment box at the start of the script - look at CurrentPlayer as an example). Variables (or constants) defined here can be accessed and change by any subroutine within the whole program - that are not specific to any one subroutine.

Global variables are ideal for 'table wide' values that you want to store (or check) within any subroutine. Such examples might be a total bonus you want to award when the player loses a ball. As the player hits certain things (or achieves certain results), you might want to add an amount to the total bonus which you award when the ball is lost.

To top

What are Subroutines?

Subroutines are a group of code statements that (in FP) are executed when something occurs. The something  is known as an event and usually relates to the ball hitting something that reacts (often by adding a score, turning on or off a light etc). Subroutines should stick to a specific task and it is bad practice to have a 'massive' subroutine that carries out a lot of different things.

Here is an example of a subroutine...

Sub bumper1_hit()
Dim bumperhitcount

    bumperhitcount = bumperhitcount + 1
    Addscore(100)

End Sub

This subroutine's code is executed when 'bumper1' is hit. In it, a bumper counter is incremented and 100 points are added to the players score (yes - Addscore is another subroutine). You will invariably end up with subroutines far larger and more complex than this but remember to keep the subroutine down to a specific task.

To top

Passing Arguments

Notice with the start of a subroutine that you have Sub mysub() - note the brackets at the end of the subroutine name. The brackets allow a subroutine to receive an argument. An argument is a variable/constant or value that the subroutine can use. The Addscore subroutine uses an argument and is called when you want to add a set amount of points to the players score. Here's another example that shows how arguments can be used:

... in a subroutine within the script

   msgstring = "Welcome to Code Corner"
   dspmsg(msgstring)

....

Sub dspmsg(msgstring)

    dispseg1.queuetext msgstring, seWipeStarRight, 200, 0, FALSE, ""

End Sub

So what is happening here? I use a subroutine in my own tables called dspmsg (Display Message). Rather than having the dispseg1.queuetext etc everywhere in my program when I want to display a message on a segment display, I use a subroutine. I set the value of msgstring to the text I want to display, call the dspmsg() subroutine and pass msgstring as the value that dspmsg() will work with. This is a way of reusing code that is not only more efficient, but makes my life as a programmer easier!

I can even call dspmsg like this...

    dspmsg("Hello World")

but I prefer to use a variable (it's just me!). Apart from having to use _hit() routines, I tend to use subroutines whenever I want to use the same code over and over. For example, suppose I have a table with 3 lanes. Each lane has a star trigger that if hit turns ON or turns OFF a light below it. I also want to rotate the lights if the player presses the flipper keys. Each star trigger will have its own trigger_hit() routine but I would use a separate subroutine to rotate the lights. Here's the code...

Sub lane1trigger_hit()

   If(lanelight1.state = bulbon) then
      lanelight1.state = bulboff
   else
      lanelight1.state = bulbon
   end if

End Sub

Now I would have 2 more subroutines like this for lane2trigger_hit() and lane3trigger_hit() (remembering to change the names of the lanelights of course!

In the 2 flipper routines (left and right flipper) I would call my rotate lights subroutine

   If (KeyCode = GetKeyCode(LeftFlipperKey)) Then
       LeftFlipper.SolenoidOn
       PlaySound "flipper"
       rotatelights()
   End If

Now for my rotatelights() subroutine...

Sub rotatelights()
Dim lt1
Dim lt2
Dim lt3

    lt1 = lanelight1.state
    lt2 = lanelight2.state
    lt3 = lanelight3.state

    lanelight1.state = lt3
    lanelight2.state = lt1
    lanelight3.state = lt2

End Sub

So no matter which flipper is depressed, a call to rotatelights() is made which carries out the switch.

To top

How Does My Code Get Executed?

Most subroutines are executed when an event occurs. This type of event occurs when a trigger event happens. A trigger event (not a trigger on a pintable) is something that happens. When the event triggers, the relevant section of code is executed. Virtually all Windows programs are event driven. For example, in a Word Processor, the user clicks on the Bold button. The event - click bold button, triggers a section of code that tells the program to produce bold text. In FP, triggers occur (usually) when something (the ball) hits something else.

A lot of controls in FP use a Control_Hit() method. So in the bumper1_hit() example the code is executed when the ball strikes bumper1. This is an important concept to grasp - especially if you have written procedural code. There is an excellent section in the FP manual under Global Methods & Variables that tells you about the existing subroutines that are automatically created when you create a new table. Read this section so that you know what happens and where as this is crucial for the non _hit() routines.

To top

Using Flags to Detect What is Going On

As you know, pinball is a fast and at times furious game with many things seemingly happening at once and every control on the table should "do something" but how do you keep track of this within your script?

One answer is to use flags. Flags are variables that store indicators and are usually ON or OFF (so you can use lights to tell what has happened). For example, in my Winter Olympics table, I created a subroutine that "adds" lights (lights up) un lit OLYMPIC GAMES lights. The subroutine will light the first unlit light it comes across. If it has to light 2 or 3 or 4 lights, it repeats the process, but because (when the subroutine is called), any light(s) may be lit, it has to test each one.

Here's the subroutine...

sub addlights(extralts)

dim x
dim y

    y = 0

    extralts = extralts * gmode

    for x = 1 to extralts
       if(olt1.state = bulboff and y = 0) then
          olt1.state = bulbon
          msgstring = "Adding an >O<"
          y = 1
       end if
       if(olt2.state = bulboff and y = 0) then
          olt2.state = bulbon
          msgstring = "Adding an >L<"
          y = 1
       end if

...Repeated for all 12 lights

       y = 0
       dspmsg(msgstring)
    next

    chkoglights()
    extralts = 0
end sub


I've cut out a large chunk of this subroutine as its the same but for all lights. Here's the problem. If I simply test each light to see if it is on or off and turn on 1 unlit bulb, I need a way to stopping the routine from turning on ALL unlit bulbs. How did I prevent this from happening? I used a flag.

The flag is the variable Y. On entering the routine, I set Y to zero. I test a light and if I switch it ON I set Y to 1. Note the if statement - if light is OFF AND Y = 0 then turn it on. Of course, if I have already set a light to ON, then Y will be 1 and therefore the light won't be turned on. Flags are very useful for this kind of thing.

To top

Using Timers in Future Pinball

I have to admit that when I first started using FP, timers confused me, so in case they confuse you too - here's how they work.

You create a timer (the small clock icon) from the 'Special' button at the bottom of the editor. You need to set a time for it. Note that the time is in milliseconds so setting a timer to 1000 will mean it is set for 1 second. You can either set the timer duration within the editor or within your script. If you are going to vary a timer's duration it is better to set it in the script.

Here's how you use them. Suppose you have a kicker hole. You want the ball to sit in the hole for a brief moment before the kicker kicks the ball out (say 1.5 seconds). Here's the order of events...

1). Enable the timer (turn it on)

2). When the time has elapsed, do something (kick the ball out)

3). Disable the timer (turn it off)

And in script form...

Sub kicker1_hit()

    kickertimer.enabled = TRUE       ' Turn on the timer having set it to 1500 in the editor

End Sub

Sub kickertimer_expired()            ' The time has run out

    kickertimer.enabled = FALSE      ' So turn OFF the timer

    kicker1.solenoidpulse()          ' Kick the ball out

End Sub

Of course, you can add scores, light lights etc as you see fit. If you remember those 3 steps when using timers, you will find them simple to use.

To top

Good and Bad Practices when Coding

There have been books written about coding standards so you might not agree with all of these things but I offer these as someone who once programmed for a living and I also offer a reason why.

Practice Good/Bad Why
Use meaningful variable names Good This causes you far less confusion than using 'x1', 'x2', 'x3' etc. In 3 months time you won't remember what the variables represent and (more importantly?) if someone else needs to look at your code, they will have far more difficulty in understanding what is going on
Indent Code Good This is not just a beautification tool but helps trap errors - particularly in IF statements. Look at the Addlights() routine above and it is easy to see which statements are carried out for each IF (and this is especially true if using IF/ELSE statements)
Comment your Code Good Not only do comments help you remember what each subroutine is doing (or someone else for that matter!) they offer a great way of finding things in the editor (Using the Find tool)
Defining flags Good This is a personal preference, but I DO tend to use X, Y, Z etc when defining a flag. When I see X, Y or Z then I KNOW that variable is simply a flag and does not contain 'real data' I use real names for variables that hold 'data'
Consistent naming Good This is something that can be extremely useful. Say you have 4 lights in a drop target called "dt1". If you use "dt1lt1", "dt1lt2" you can copy and paste lines and change the numbers - far simpler that calling them something like "droptargetleftouterlight", "droptargetleftinnerlight". These names (although potentially more meaningful are pain to copy and paste).
Code Obfuscation Bad Code obfuscation is the act/art of changing all your variable names to something meaningless (usually done once a program is complete using global find/replace). I've worked on obfuscated code and it was probably easier to ditch it and start from scratch. You may have finished this table but I often find I pinch bits of code from previous tables. If I'd obfuscated it I wouldn't be able to do it.
Changing a variables data type Bad Although VB Script allows it, it is not a good idea to change the data type of a variable part way through a program. It's confusing - particularly if you need to debug your code. Better to use 2 variables rather than 1 and keep reassigning it
Adopting a standard Good Try to adopt a standard method of naming variables throughout your table. Do you use "light#" or "lt#"? Whichever, try to stick with it. (I do tend to mix them a bit - I use "light" for 4 or less associated lights and "lt" for more. I also try to use standard naming (like X, Y and Z for flags rather than sometimes use X, Y and Z and other times use A, B and C. It doesn't matter to the program, but it makes my life easier.
To top


AND and OR - An Explanation

These 'words' are typically used in IF statements. The IF statement is one of the most powerful commands in programming as it allows choice. The syntax is:

      IF(condition 1 is true) THEN
          do something
      END IF

Sometimes we want to use more than one condition and this is where AND and OR come into play. Here's an example:

    IF(bonuslight1.state = bulbon AND bonuslight2.state = bulbon) THEN
       bonuslight3.state = bulbon
    END IF

So what we are saying here is that if bonuslight1 is ON and bonuslight2 is ON turn on bonuslight3

We can also use OR and the thing to remember here is that:

    Use AND - ALL conditions must be true for the code to be executed
    Use OR   - Only one condition needs to be true for the code to be executed

There is a 3rd option - NOT and in this case NONE of the conditions must be true for the code to be executed.

To top


Handling Drop Targets

At the heart of most pintables are dropped targets. This section will deal with how to set up a bank of 4 targets, each target having a light in front that is turned on as each target is struck. Here's an example taken from my Dragons' Lair table...

E.G. 4 targets with each target having a light in front. As an individual target is struck, the light is turned on.

For this example, we shall assume that 500 points is added to the player's score for each individual target and if all 4 are knocked down, the player is awarded an additional 5000 points. We will flash the lights when all targets have been knocked down.

The code will assume that the group of targets is called "DropTarget1" and the 4 lights are "Dt1Lt1" to "Dt1Lt4"

First of all we need to name the target (as above) and each of the 4 lights in the editor.

Having done that, we can turn our attention to the script side of things.

Here's the section of code...

Sub DropTarget1_hit()

     Select Case(fpEventID)
          Case 1: Dt1Lt1.state = bulbon
          Case 2: Dt1Lt2.state = bulbon
          Case 3: Dt1Lt3.state = bulbon
          Case 4: Dt1Lt4.state = bulbon
     End Select

    if(DropTarget1.dropped = TRUE) then
          addscore(5000)
          DtLt1.FlashForMs 100, 50, bulboff
          DtLt2.FlashForMs 100, 50, bulboff
          DtLt3.FlashForMs 100, 50, bulboff
          DtLt4.FlashForMs 100, 50, bulboff
          DropTarget1.solenoidpulse()
     else
          addscore(500)
     End if

End Sub

So what is happening here? Lets look at the first section of code - the Select Case statement. Select Case statements are a neat way of having multiple IF statements without having to have, multiple IF statements! The fpEventID is a special variable that is used as the subject of the test (so what we are saying here is "IF fpEventID = 1 THEN turn ON bulb 1". The fpEventID stores which individual target out of a bank of targets has been hit. You can also use your own variables in Case statements. In this example, target 1 or target 2 or target 3 or target 4 has been hit (it must have been hit because this subroutine is only ever run when the the target bank has been hit).

So for each possibility (1 to 4), we turn ON the corresponding light (so make sure light 1 is in front of target 1, light 2 in front of target 2 etc). You can tell in the editor which target is which as each is numbered.

We could at this point add 500 points but this is inefficient because we would need an "addscore(500)" after each statement that turns on a light. We'll add the score in the next section of code.

The 2nd block of code (the 2nd IF statement) handles the situation of when all the targets have been struck. We test to see if the target has been dropped and if it has, we add the 5000 points. We then flash the lights a couple of times "FlashForMs" and when that is complete, the bulb is turned OFF (hence the bulboff at the end of the FlashForMs command). Finally we pulse the target which resets all the individual targets back up again so that the player can hit them again. If you don't do this, the targets will stay down.

If the target HAS NOT been dropped (in other words, a target has been hit but there are still some targets standing), we add 500 points. Notice that by doing the addscore(500) this way, we only need one statement rather than having 4 separate addscore(500) statements.

What else can you do with targets? The above section of code will cover the most usual aspect of handling targets but you can do other things as well. Here are some possible suggestions for when you "drop all targets"

  • Light another bonus light
     
  • Open up another part of the table (by opening a diverter)
     
  • Start a sub game (you might want this to start when all banks of targets have been dropped). You could do this by adding a value to a variable and then test the variable. For instance, suppose you had 3 banks of targets and if the player knocks down all 3 sets you start a sub game (or multiball or whatever). Assign each target bank a number, lets say '1' for bank 1, 10 for bank 2 and 100 for bank 3. When a bank is knocked down, add the corresponding value to the variable. If the variable = 111 then all 3 target sets have been hit and you can start your sub game. Of course, you will need to set a flag after the first time a bank is dropped in case the player knocks down the same set twice (which would mean that you could end up with 112 rather than 111)
     
  • Start a light sequence
     
  • Play a special sound

In fact, you can do anything you like!
 

To top

Creating an Attract Mode Sequence

An attract mode sequence is a light show for when the table is not actually in play (all the flashing lights that occur trying to lure you into playing a game). In FP, one of the ways to do this is by using the .set bulbblink command.

Here's how it works:

Assume we have 4 lights that are laid out on the table vertically (1 bulb beneath another). Bulb 1 is at the top and Bulb4 at the bottom. In the SetAllLightsForAttractMode() subroutine we use a .set bulbblink command to tell the system how we want the bulbs to blink. For this example, we will start at bulb1 then bulb2 then bulb3, bulb4 then go back to bulb3, bulb2 then bulb1. After that we will flash all the bulbs twice. Here's the code using the colours that appear in the script editor:

     bulb1.set     bulbblink, "1000000101010", 200
     bulb2.set     bulbblink, "0100001001010", 200
     bulb3.set     bulbblink, "0010010001010", 200
     bulb4.set     bulbblink, "0001100001010", 200

So what is going on here? The way to "read" what is going on is to look at the purple 1's and 0's in columns. The 1st column is "1000" which means bulb1 is ON whilst bulbs 2, 3 and 4 are OFF. The 2nd column is "0100" which means bulbs 1, 3 and 4 are OFF whilst bulb 2 is ON. following this sequence we can see that the bulbs are turned on in this order:  1 - 2 - 3 - 4 - 4 - 3 - 2 - 1 then all OFF then all ON which is repeated once.

The '200' at the end of the line tells the system how long the bulb should be on in milliseconds so 200 is 1/5th of a second.

To alternate bulbs (1 and 3 ON then 2 and 4 ON) we would use something like this:

     bulb1.set     bulbblink, "1010", 200
     bulb2.set     bulbblink, "0101", 200
     bulb3.set     bulbblink, "1010", 200
     bulb4.set     bulbblink, "0101", 200

You can use all manner of variations to create an attractive light sequence!

To top

Using a FOR/NEXT Loop

Quite often within a pintable, you will want to create a loop that is repeated so many times (perhaps to carry out a bonus sequence). One way to do this is to use a FOR/NEXT loop. In my Winter Olympics table, I used a loop to light a certain number of letters for the OLYMPIC GAMES lights. Players could have up to 6 lights lit depending on what they have achieved and the difficulty level.

Here's the syntax...

       For x = 1 to 5
               Do something...
               any amount of code can go here
       Next

This loop will be executed 5 times (you can have any number here), or you can use a variable in place of the '5'. Here's an example which is a subset of my Olympic Games table.

Note the comments in this code segment. (Shown in Fuchsia)

    Dim LoopCounter    ' Defined at the top of the script so that it is a global/public variable

    '   This is the code for the light a certain number of lights out of a sequence

    Sub LightLights(LoopCounter)
    Dim x

   
' Carry out the loop 'loopcounter' times (even if loopcounter is 1 this is still OK)
    For x = 1 to LoopCounter
   
' If the previous light is ON turn the next light ON
          if(light4.state = bulbon)  then light5.state = bulbon
          if(light3.state = bulbon)  then light4.state = bulbon
          if(light2.state = bulbon)  then light3.state = bulbon
          if(light1.state = bulbon)  then light2.state = bulbon
          if(light1.state = bulboff) then light1.state = bulbon
    Next

    End Sub

You can basically ignore the IF statements as this can be any code you want to place inside the FOR/NEXT loop. The key things to remember here are:

1). Make your loop counter (if you are going to use a variable) a global/public variable

2). Initialise the loop counter (this can be done at table load time) but needs to be reinitialised after every ball/game

3). Increment the loop counter when required (perhaps when a bank of targets has been dropped)

4). Use the FOR/NEXT loop to loop through 'loopcounter' times

To top

Using the Flippers to Rotate a set of Lights

This is an extremely common pintable feature where the player can use the flippers to rotate a set of lights - often, these lights are at the top of the table (or near the flippers themselves) so that an entire bank of lights can be lit - often employed as a way of getting a bonus multiplier or other game feature.

You can see that the L and A of the word LAIR has already been lit. The player uses the flippers to move the lights so that when the ball goes into a lane, an unlit letter can be lit (as shown in the above screen sample).

How do you allow the player to do this? Here's the code...

     Sub RotateLairLights()

     Dim tmp1
     Dim tmp2
     Dim tmp3
     Dim tmp4

     tmp1 = Llight.state
     tmp2 = Alight.state
     tmp3 = Ilight.state
     tmp4 = Rlight.state

     Llight.state = tmp4
     Alight.state = tmp1
     Ilight.state = tmp2
     Rlight.state = tmp3

     End Sub

As the subroutine is entered, the states of the 4 bulbs (that spell LAIR) are stored in temporary variables (tmp1, tmp2 tmp3 and tmp4)

The state of each actual bulb is reassigned (So light1 takes on light4's state, (the L of LAIR), light2 is assigned light1's state and so on). It does not matter whether any or all bulbs are lit, they will rotate!

The final stage is to call this subroutine from the FuturePinball_KeyPressed subroutine (the easiest place to put the call is immediately after the 'Playsound "Flipper"' command. Don't forget to call the routine from both the left AND right flipper (so the call she be duplicated for each flipper. Of course, you could be clever and rotate the lights one way for left and the opposite direction for right!

To top

Using a Bonus Light Sequence (Code supplied  by Brother_B)

We have all played tables where, at the end of a ball, a bonus sequence counts down but how do you do this in Future Pinball without having timers for every single bonus light? Here's how...

Sub AdvanceBonus(points)
   If (fpTilted = False) Then
      Bonus = Bonus + points
      If Bonus = 10 Then
         BonusLight10.State = BulbOn
         BonusLight1.State = BulbOff
         BonusLight2.State = BulbOff
         BonusLight3.State = BulbOff
         BonusLight4.State = BulbOff
         BonusLight5.State = BulbOff
         BonusLight6.State = BulbOff
         BonusLight7.State = BulbOff
         BonusLight8.State = BulbOff
         BonusLight9.State = BulbOff
      End If      
      If Bonus = 20 Then
         BonusLight20.State = BulbOn
         BonusLight1.State = BulbOff
         BonusLight2.State = BulbOff
         BonusLight3.State = BulbOff
         BonusLight4.State = BulbOff
         BonusLight5.State = BulbOff
         BonusLight6.State = BulbOff
         BonusLight7.State = BulbOff
         BonusLight8.State = BulbOff
         BonusLight9.State = BulbOff
      End If
      If Bonus < 10 Then
         BonusLights(Bonus).State  = BulbOn
      Elseif Bonus > 10 And Bonus < 20 then
            BonusLights(Bonus - 10).State  = BulbOn
      Elseif Bonus > 20 Then
            BonusLights(Bonus - 20).State  = BulbOn
      End If
      If Bonus > 29 Then Bonus = 29 End If
   End if
End Sub

 

This subroutine turns on (and off) the various bonus lights (in this example, up to a maximum of 29) That is lights 1 to 9 plus a 10 and a 20 light)

At the end of the ball you want to collect the bonus. If you have a multiplier, then store everything in temporary variables thus...

Sub BonusTemp()
   BonusTmp = Bonus 'Store the Bonus value
   BL20Tmp  = BonusLight20.State   'Store the State of the lights
   BL10Tmp  = BonusLight10.State
   BL1Tmp   = BonusLight1.State
   BL2Tmp   = BonusLight2.State
   BL3Tmp   = BonusLight3.State
   BL4Tmp   = BonusLight4.State
   BL5Tmp   = BonusLight5.State
   BL6Tmp   = BonusLight6.State
   BL7Tmp   = BonusLight7.State
   BL8Tmp   = BonusLight8.State
   BL9Tmp   = BonusLight9.State
   BonusTimer.Set True, 150 'Start the timer for the nice countdown
End Sub

Then we have the actual bonus countdown and lights out. The speed of the countdown is controlled by the timer settings. (Note the '150' in the penultimate line of this subroutine)

Sub BonusTimer_Expired()

   If Bonus = 19 then
      BonusLight20.State = BulbOff
      BonusLight9.State = BulbOn
      BonusLight8.State = BulbOn
      BonusLight7.State = BulbOn
      BonusLight6.State = BulbOn
      BonusLight5.State = BulbOn
      BonusLight4.State = BulbOn
      BonusLight3.State = BulbOn
      BonusLight2.State = BulbOn
      BonusLight1.State = BulbOn
   End If
   
   If Bonus = 9 Then
      BonusLight10.State = BulbOff
      BonusLight9.State = BulbOn
      BonusLight8.State = BulbOn
      BonusLight7.State = BulbOn
      BonusLight6.State = BulbOn
      BonusLight5.State = BulbOn
      BonusLight4.State = BulbOn
      BonusLight3.State = BulbOn
      BonusLight2.State = BulbOn
      BonusLight1.State = BulbOn
   End If

   If Bonus > 20 Then
      BonusLights(Bonus - 20).State  = BulbOff
   End If

   If Bonus < 20 And Bonus > 10 Then
      BonusLights(Bonus - 10).State  = BulbOff
   End If

   If Bonus < 10 Then
      BonusLights(Bonus).State  = BulbOff
   End If

   If Bonus < 2 And BonusX < 2 then 'If everything is done then end
      BonusTimer.Set False
      EndOfBallTimer.Set true, 10
   ElseIf Bonus < 2 Then
         Bonus = BonusTmp + 1 'You must add one, otherwise it's lost.
         BonusXLight(BonusX).State = BulbOff
         BonusLight20.State = BL20Tmp 'Temp state of the lights
         BonusLight10.State = BL10Tmp
         BonusLight9.State  = BL9Tmp
         BonusLight8.State  = BL8Tmp
         BonusLight7.State  = BL7Tmp
         BonusLight6.State  = BL6Tmp
         BonusLight5.State  = BL5Tmp
         BonusLight4.State  = BL4Tmp
         BonusLight3.State  = BL3Tmp
         BonusLight2.State  = BL2Tmp
         BonusLight1.State  = BL1Tmp   
         BonusX = BonusX - 1
   End If
AddScore(1000) 'Add some score
PlaySound "Bonus" 'Play a sound
Bonus = Bonus - 1 'Decrease the bonusvalue
End Sub

So it's done by using a single timer over and over until all the lights have been extinguished.

Thanks Brother_B!

To top

Embedding the Bonus Light System into your table

Using the previous article as a basis for a bonus system, this section looks at how you embed this code into your own table to get it to work.

Lets start with the declarations. These occur right at the top of the script just before the "Defined Script Events" section.

Dim Bonuslts(29)
Dim BL20Tmp
Dim BL10Tmp
Dim BL1Tmp
Dim BL2Tmp
Dim BL3Tmp
Dim BL4Tmp
Dim BL5Tmp
Dim BL6Tmp
Dim BL7Tmp
Dim BL8Tmp
Dim BL9Tmp
Dim Bonus
Dim Bonustmp

set bonuslts(1) = bonuslt1
set bonuslts(2) = bonuslt2
set bonuslts(3) = bonuslt3
set bonuslts(4) = bonuslt4
set bonuslts(5) = bonuslt5
set bonuslts(6) = bonuslt6
set bonuslts(7) = bonuslt7
set bonuslts(8) = bonuslt8
set bonuslts(9) = bonuslt9
set bonuslts(10) = bonuslt10
set bonuslts(20) = bonuslt20

We have 2 blocks of code here - the Dim Statements that tell the script that these variables can and will be referred to by any subroutine in the script. Then we have a series of Set statements so what is happening here?

Notice the very first Dim statement? It's different from the others because it has a number (29) after it. This means that Bonuslts is in fact an array which means that it is a variable that can contain a list of values. When we access an array we have to state the array name AND which element (or list item) we want to use. Bonuslts has a 29 element array (which relates to 29 bonus lights 1-9, 10 - 19 and 20 - 29)

Look at the 2nd block of statements - the set statements. Here we are assigning individual lights on the table to elements in the array. Now you may be wondering where lights 11 to 19 and 21 to 29 are. We have made this more efficient by re-using the 1-9 lights. When the player has light 9 lit and hits the 10th, lights 1 to 9 are turned off and light ten is lit. When the bonus is increased from 10 to 11, we leave the 10 light on and light the 1 light. When the 10 light and the 1 to 9 lights are lit, the next increase turns off the 10 light and the 1 to 9 lights and turns on the 20 light where the process starts again up to a maximum of 29. Play my Blue Mood table to see this in operation.

So at this state, we have defined the variables and told the array which lights are assigned to which elements.

We now need a way of advancing the bonus and this is carried out when certain objectives have been reached. For example...

Sub kicker2_hit()

   kicker2timer.enabled = TRUE
   upflash.flashforms 1000, 100, bulboff
   advancebonus(1)

   if(greenlight.state = bulbon) then
      moodlt1.state = bulbon
      greenlight.state = bulboff
   else
      moodlt3.state = bulbon
      greenlight.state = bulbon
   end if

   chkbmoodlts()
end sub

Notice the advancebonus(1) statement? (You can ignore the rest of the code in this snippet.) This is how we get the next light on the bonus lit up and you will have an advancebonus(1) statement wherever you want to increase the bonus lights. Want to have differing awards? You could have something like this:

   For x = 1 to BallsOnPlayfield
      advancebonus(1)
   next

This code would increase the number of lights based on the number of balls currently on the playing field which would differ during a multi-ball event.

OK to recap...

We have our variables set up and we have gone through the script adding the "advancebonus(1)" statements everywhere we want to up the bonus lights. Now it's time to deal with collecting the bonus when the ball drains. (You can add this statement right after the (playsound "Drain") statement.

   for x = 1 to bonus
      bonustemp()
      if(x = bonus) then
         bonuscomplete = 0
      end if
   next

Remember all those advancebonus(1) statements? Well every time these statements are called the value in brackets (1) was added to a variable called "bonus". So bonus knows how many lights have been turned on. We create a loop to execute 'bonus' number of times - once for each lit bulb. Bonustemp is called which stores the state of each light and then starts the timer. When the timer expires the _expired subroutine turns off the highest light, adds a score and then leaves. This is repeated "bonus" number of times until all the lights have been extinguished and he bonus has been paid out.

To see this script in action, download and play my Blue Mood table where this code is used.

To top

Creating a Random Event

Within a table, it can be good to include a 'Random Event' that occurs but how is this achieved within FP? To do this, we need 2 things. 1st, we need to generate a random number and 2nd we need to take action based on the random number. Of importance when creating a random number is that we (usually) want to create a random number within a specific range such as "A random number between 1 and 6" (to perhaps simulate the roll of a dice). How is this achieved? The following code can be used...

     i = INT(RND(1)*6)+1

Lets breakdown this statement. First of all, the variable 'i' will be the variable that will hold the random number. The INT function tells the system to return only the integer (whole number) portion of the random number. So if the computer generated a random number of 2.308765263421 then only '2' will be returned (the integer part of the number). The RND(1) function is the function that creates the random number. The '*6' means multiply the random number by 6 (the actual random number is between 0 and 1), so we need the * 6 to generate a larger random number. Notice how the * 6 is within the brackets of the INT function so that we will get a whole number only. A crucial part of this statement is the + 1 at the end. Without this, this statement would generate a random number between 0 and 5 but we need a random number between 1 and 6.

So to create a random number between 1 and particular number, replace the *6 with whatever number you want (and yes, you can use a variable here so you could have * My_Variable if you wish). If you want to create a random number between 40 and 50 you could use...

     i = INT(RND(1)*11)+39

There are some odd numbers here! We need a random number between 1 and 11 as the range between 40 and 50 is 11 not 10. We add 39 at the end so that 40 can be generated (if the INT function returns '1' this will be added to 39 giving 40).

OK - So we have our random number (using the dice example of a random number between 1 and 6), so what happens now? The easiest way to handle the random number is by using a SELECT statement like this...

    Select Case i
         Case 1: rndevent1()
         Case 2: rndevent2()
         Case 3: rndevent3()
         Case 4: rndevent4()
         Case 5: rndevent5()
         Case 6: rndevent6()
    End Select

Depending on the random number (i), 1 of 6 subroutines (rndevent1() to rndevent6()) will be executed. Of course, you can have any subroutine you like being executed if you wish or even a few lines of code depending on what you want to do. Here are some ideas where you might want to use a random number event (there are plenty more, these are just to give you an initial idea)

  • Start a random game mode (In the above example, you would have 6 different game modes)
     
  • Assign a bonus award (Just include 'i' in the calculation or have 6 different calculations)
     
  • Open/Close gates/diverters based on the random number
     
  • Turn On/Off lights based on the random number
     
  • Add a random amount to a jackpot
     
  • Set a random amount of points for hitting an object (target, bumper, trigger etc)

I am sure you can think of even more than this list!

To top