Visual Pinball Basic Code Explanation


back to index         -         previous page         -         next page

- Dim, the start of the script
- Sub-Routines
- If...Then.../If...Then...Else...
- Calculating
- Commands
- Examples


Less is More !!!
Try to keep the script as short as possible.
If you find a way to save only a few lines, change it, it's worth it.





Dim

Always put Dim's at the start of script !
These are defined variables that are kept in memory, even if the sub-routine has finished.
A simple reminder... Dim = Dump in Memory.
Each script has to begin with all variable definitions, Dim's.
Don't put the Dims in any other place than at the top of the script.
A new table has no Dim's, so you wont find any Dim's at the start of the script.
A complete tablescript can have 20 variables or much more.
The Dim's are used to keep track of scores, store information,
bring variables from one routine to another or whatever use there can be.
They can contain either numbers or text.
Mostly, Dim's are used to make the script shorter, because you have only 1 big sub-routine wich
decides the value/content of a Dim. In the rest of the script, you can just use the result of
the routine by using the Dim with just 1 simple word. This also increases performance, because
there's less calculating going on.
Where you place the name of the Dim in a sub-routine, the content of that Dim will be used.
Only use a Dim when the value is a real variable.
Only change the content/value of a Dim when it's needed.
As with everything, Less is More.
1 Dim can be used for multiple purposes.
In my bonusroutine, I use a Dim named BonusTemp. When there is a ball in play, the bonusroutine
isn't running. This Dim therefore can be used in something like an adventure routine.
Keep in mind that in this example, the information in the Dim is lost when the bonusroutine
runs again. Therefore only information needed during ball-in-play can be stored here.
Dim Score
Dim HiScore
Dim Bonus
Dim BonusMultiplier
Dim Turn
Dim ExtraBallCount
Dim SongName
Dim RandomReward
.....

Some ways to change the value of a Dim, using above examples.
These are lines as they could be used in a sub-routine.

Score=Score+100000
HiScore=Score
BonusMultiplier=BonusMultiplier+1
Bonus=Bonus*BonusMultiplier
BonusMultiplier=0
Turn=1
ExtraBallCount=ExtraBallCount-1
SongName="Background_Music_1.mp3"
RandomReward="You found a treasure! Reward: 500.000 Points"


Go to Menu


Sub-Routines

Sub-Routines are what makes everything happen.
It doesn't matter where a sub-routine is placed in the script.
But 1st: always the Dim's !

A routine starts at the top and works it's way to the bottom.
Each line is proccessed and finished before the routine goes to the next line.
Changing the place of a command in the routine, can drasticly change how it works.
Take the time to think what should happen first and place that at the top of the routine.
Activating a timer with
Object.TimerEnabled=True just activates the timer.
The routine won't wait for the timer to finish before continuing to the next line.


Sub AdventureStart()
It starts with Sub followed by a unique name and brackets().
Give it any name you like, as long as it is unique. Best use a name that shows what the routine does.
This will be very helpfull when you have a large script.


Sub AdventureStart(choice)
Between the brackets, you can place the name of a variable that is only used in this specific sub-routine.
The name of the variable is all up to you. I like to keep these unique in the script also.

In this example, choice is the variable.
Since the variable is only used in this sub-routine, there is no need to keep it in memory.
There is no need to make a Dim named choice.
When you start this sub-routine somewhere else in the script with a line like:
AdventureStart(2),
the AdventureStart sub-routine will run with the
choice-variable set at 2.
Somewhere in the AdventureStart routine there will be a line like:
If choice=2 Then...

End Sub
It ends with End Sub.
Everything between Sub and End Sub is 1 routine.
End Sub is always needed at the end of the routine. It tells the computer that the routine is finished.
Sometimes a routine can get very large, try to keep them as short as possible.
Most of the time, there are repeating events that can be done by a seperate sub-routine.
It may also be possible to split the sub-routine, having 2 or 3 small ones rather than 1 large one.


Exit Sub
This exits the sub-routine. The routine stops running and doesn't look at the rest of the code.
This is something different than End Sub. End Sub is part of the routine code needed for the computer.
Exit Sub is a command, executed at the moment the routine comes to that point.



Some general object sub-routines
These are the startlines, they are followed by code and End Sub.
Use the name you've chosen for the object.
If an object is named BigBlock, use Sub BigBlock_Hit()

Sub Object_Hit() standard hit-routine, this is activated when the ball hits the object
Sub Object_Timer() this happens when the timer of an object ends after it's interval time
Sub Object_Init() this happens at the start (initialisation) of the table
                I only use one to play a opening sound and activate my ResetTable() routine.


Some object specific sub-routines
These are the startlines, they are followed by code and End Sub.
Use the name you've chosen for the object.
If an object is named LeftSpinner, use Sub LeftSpinner_Spin()

Sub Spinner_Spin() this is activated for each rotation the spinner makes
Sub Wall_Slingshot() this is activated when the slingshot of a wall is hit
                in edit mode, rightclick the dot on a corner of a wall and choose slingshot

Sub Table1_MusicDone() This is activated when the background musicfile has ended.


Go to Menu       Go to Examples


If...Then... / If...Then...Else...

If .... Then ... End If
If the named requirement is met, the commands between Then and End If are executed.
For each
If there has to be an End If.
If you want something to happen when multiple requirements are met, just use
AND.
You can do all sorts of calculating in the requirement, using
+ - * / mod < = > and ( ).
If xxx Then xxx End If xxx does almost the same as If xxx Then xxx Else xxx End If.
Most of the time you will use If/Then. Sometimes If/Then/Else is easier.


<   =   >
These operators are used in the requirementpart of If/Then.
It compares 2 values to see if the requirement is met.
< ... is less then (1st value is lower than the second value)
= ... is equal to (both values are the same)
> ... is greater than (1st value is higher than the second value)

There are loads of examples for requirements and the following commands on this page.
If you see them, you will get the picture of how it works.
The names you see in the requirements are variables, comming from either a Dim or the routine itself.



Go to Menu       Go to Examples


Calculating

There will be some calculating going on in your table.
Less is More, try to keep the calculating to a minimum to increase performance.
/ (dividing) takes more proccessingpower than * (multiplying).
It's better to do
QuestValue * 0.2 then QuestValue / 5.
There may be more ways to calculate, but these are the only ones I use to build tables.

+ - * / ( ) int mod rnd
Calculating can be done almost everywhere in a routine.
If the routine uses a number, a formula can be placed to get that number.
A formula can be very simple or more complex.
Just look at the examples, you will get the idea.
While there is a ball in play, keep the formulas as simple as possible to increase performance.
Use the complex formulas before the start of a turn or in the End Turn routines.
Use a Dim to remember the outcome of the formula and use the Dim when the ball is active.


+   -
These are simple: add substract.

/   *
These are simple: divide multiply.
Divide is a bit tricky. Somehow it's more difficult for the pc to calculate.
Try to use multiply instead.
If the result of the formula can be a fractional number, use
int to reduce it to an integer.
10 / 3 = 3.3333333333333333 wich takes up a lot of unnecesary computing power.
int(10 / 3) = 3. This is a lot easier for the computer.
Even better: 10 * 0.33 = 3.3, this can be made an integer: int(10*0.33) = 3


(   )
the brackets are used to give a part of a formula priority.
First the part between the brackets is calculated, then the complete formula is proccessed.
For each opening-bracket there has to be a closing-bracket.
There is no limit to the amount of brackets used in a formula.
Brackets can also be used even when they are not needed...
Score+25 does the same as (Score+25).
Just look at the examples and you'll get the idea.


int
This operator turns the value into an integer.
A fractional value is cut off and leaves only the whole numbers.
int(1424.36) will become 1424.
int(0.99) will become 0.


mod
This operator substracts the given amount from a variable untill it can't do so anymore.
What is left is given as outcome.
I always place the variable and the mod between brackets, this makes reading the code easier.
Some examples with possible values of variables.
In a routine, you would type the name of the variable, like Score mod 100.
Here I will only use the value contained in the variable.
(126500 mod 1000) gives 500, (80455 mod 5) gives 0, (5375 mod 50) gives 25
(1005 mod 10) gives 5, (254399 mod 3) gives 2, (3 mod 2) gives 1, (10 mod 10) gives 0.


rnd
This operator gives a random number between 0 and 1.
You will have to multiply it and make it an integer to suit your needs.
1 never is the outcome of rnd !
int(rnd*10) gives a random value ranging from 0 to 9.
To get a random value between 1 and 10, use int(rnd*10) + 1.
To get a random value between 1 and 15, use int(rnd*15) + 1
To get a random value between 1 and 20, use int(rnd*20) + 1
Some people first place the command Randomize before the line containing rnd:
Randomize
EndMatchValue = 10*(int(rnd*10))
I have tested it myself and found no difference between using it and not using it.
If you don't want the same number to come up twice, you will have to write additional code
to make sure that doesn't happen.



Go to Menu       Go to Examples


Commands

Commands are things that happen at the moment the routine reaches the command.
Nothing happens if no command is given to make it happen.
Calculating commands are obvious. Just look at the examples to get the idea.
Objects don't work if there is no routine (with commands) that controls them.
Here is a list with commands to control objects. Use any name you like for objects.
Use the name you've chosen for the objects in the commands.
If a light is named LeftEye, use LeftEye.State=1

some general commands:

routine() this starts the named routine
Object.Enabled=True True=active, False=off (if possible)
Object.DestroyBall destroys the ball if present at the object (if possible)
Object.CreateBall creates a ball at the object (if possible)
Object.CreateBall.Color=RGB(255,0,128) creates a ball in the specified color (if possible)
        Red/Green/Blue : the value ranges from 0 (no color) to 255 (full color) for each color.

PlayMusic "FileName.mp3" Plays the mp3-file from the /music directory in visual pinball
EndMusic this stops the music
PlaySound "SoundName" this plays a soundfile included in the table. No extension!

some object specific commands:

Light.State=0 0=off, 1=on, 2=blinking (interval=ms, pattern uses 0/1, [001] = off-off-on)
Target.IsDropped=True True=target is down, False=target is up and can be hit
LeftFlipper.RotateToEnd RotateToEnd is flipper up, RotateToStart is flipper down (rest)
Plunger.PullBack
Plunger.Fire
Kicker.Kick direction, speed direction: 0=up, 90=right, 180=down, 270=left, 360 degrees total
                speed: 1=slow, 40=fast (perhaps 100 is max?)

TextBox.Text="Type Your Text Here" displays the text in a textbox
TextBox.Text="" clears the textbox from any text or number
TextBox.Text=VariableName shows the value/content of a variable in a textbox
TextBox.Text=FormatNumber(variable,0,-1,0,-1) shows the value of a variable as 999,999,999
TextBox.Text=VariableName & " type your text here" the & lets you combine variables and text


Go to Menu


Examples

Here are a load of examples for requirements and the following commands.
If you see them, you will get the picture of how it works.
The names you see in the requirements are variables, comming from either a Dim or the routine itself.

The part in the End-Game routine that checks if there is a Hi-Score.

If HiScore < Score Then
HiScore = Score
HiScoreBox.Text=FormatNumber(HiScore,0,-1,0,-1)
MainTextBox.Text="Hi-Score, ConGrAtULaTioNs !"
End If

The Number Match part in the End-Game routine.
The scores in the table are all 10 or a factor of 10, like 10, 50, 100, 250, etc...
Score mod 100 gives 00, 10, 20, 30, 40, 50, 60, 70, 80, 90.

The EndNumberMatch is a Dim, set with random.
EndNumberMatch = 10*(int(rnd*10))
If (Score mod 100) = EndNumberMatch Then
MainTextBox.Text="MATCH!.... EXTRA BALL"
Turn=Turn-1
StartNewBall()
Exit Sub
End If

This checks who wins in a 2-player game, using if-then-else.
First it checks to see if it's a draw.

Sub CheckWinner()
If ScoreP1=ScoreP2 then
MainTextBox.Text="IT'S A DRAW"
Exit Sub
End If
If ScoreP1 > ScoreP2 Then
MainTextBox.Text="PLAYER 1 WINS"
Else
MainTextBox.Text="PLAYER 2 WINS"
End If
End Sub

A part of a quest target hit routine.
If 12 < Quest1Hits < 15 AND QuestActiveLight.State=1 Then
MainTextBox.Text= Quest1Hits & " Victims Rescued, almost there."
End If

The complete routine to clear the MainTextBox, using it's build-in timer.
Text1Count is a Dim. The value is set in the routine where the MainTextBox timer is activated.
This gives the freedom to use 1 timer for different times. The value is set in integers.
Text1Count=5 will take five times the Timer Interval set in the MainTextBox.

Sub MainTextBox_Timer()
Text1count=Text1count-1
If Text1count=0 Then
MainTextBox.TimerEnabled=False
MainTextBox.Text=" "
NrBox.Text=" "
End If
End Sub

The complete routine to check a set of targets.
In the hit-routine of each target there is the command CheckTopTargets().

Sub CheckTopTargets()
If TTarget1.IsDropped=True And TTarget2.IsDropped=True And TTarget3.IsDropped=True Then
PlaySound "TopTargets"
ResetTopTargets()
End If
End Sub

A complete, more complex hit-routine for a kicker.
1st, it always gives points and bonus.
The kicker is used in a quest, together with 2 other targets.
It also starts a quest when it can be started.
Otherwise it just releases the ball, using the timer.

Sub TarPitKicker_Hit()
AddScore(175)
AddBonus(10)
If AdventureLight.State=1 And MisLight3.State=2 And TarPitLight.State=2 Then
TextBox1.Text="Tar Pit visited"
PlaySound "TW-Jungle"
TarPitLight.State=0
If DCaveBottomLight.State=2 And BearCaveLight.State=2 Then
AttackText.Text="Mine-BearCave"
End If
If DCaveBottomLight.State=2 And BearCaveLight.State=0 Then
AttackText.Text="Mine"
End If
If DCaveBottomLight.State=0 And BearCaveLight.State=2 Then
AttackText.Text="BearCave"
End If
CheckJungleQuest()
TarPitKicker.TimerEnabled=True
Exit Sub
End If
If AdventureLight.State=1 And MisLight3.State=2 And TarPitLight.State=0 Then
CheckJungleQuest()
TarPitKicker.TimerEnabled=True
Exit Sub
End If
If MissionStartLight.State=2 And CountDownTimer.Enabled=False Then
MissionStartLight.State=0
MissionStart()
End If
TarPitKicker.TimerEnabled=True
End Sub

A shoot-routine for a kicker that can release the ball in multiple directions.
This way you don't have to rember or look up what the right direction was.

Sub ShootMiddle(dir)
If dir=L Then
MiddleKicker.Kick 233, 5
End If
If dir=M Then
MiddleKicker.Kick 180, 5
End If
If dir=R Then
MiddleKicker.Kick 127, 5
End If
End Sub

A complete routine that releases a ball at a chosen point.
The 4 release points are in a differnet places on the table, 4 kickers total.

Sub BallDrop(placing)
If placing=1 Then
BallDropper1.CreateBall
BallDropper1.Kick 180,4
Exit Sub
End If
If placing=2 Then
BallDropper2.CreateBall
BallDropper2.Kick 166,4
Exit Sub
End If
If placing=3 Then
BallDropper3.CreateBall
BallDropper3.Kick 152 ,4
Exit Sub
End If
If placing=4 Then
BallDropper4.CreateBall
BallDropper4.Kick 138 ,4
Exit Sub
End If
End Sub

You can also use variables like Dims to automate a routine.
This works in all cases the variable is a number.
Just make sure the variable has a logical value for the object that uses it.
Let's say the Dim is BallSpeed. The kicker uses this variable as speed when it kicks.

...
Kicker.Kick 180, BallSpeed
...


Go to Menu       Go to Examples