Tutorial FP Wecoc's collection of script snippets

Future Pinball

Wecoc

Pinball Wizard
Joined
Dec 7, 2021
Messages
63
Reaction score
100
Points
40
Favorite Pinball Machine
Cirqus Voltaire
Future Pinball's Manual is great for scripters, since it gives detailed info on which functions you have available for your table objects. That being said, it doesn't showcase all the options, and that means there are some things you can do on your tables that probably many scripters don't know about, and in some cases those can be a life changer.

Of course, no wonder some of these things are not included on the guide, since I can't find a single use case for them. For example, did you know sequence effects (Light Sequencer effects, Queue Texts in DMD & Display, etc.) have an extra option to apply the last one used? :shrug_no:

I'll be posting on this topic a collection of the (non-BAM) code snippets I find more useful, and probably I'll also include a few more advanced stuff later, this way even the expert coders may find something new to play with.

1. Object properties: Introduction​

Let's talk nomenclature just a little, to make sure we're on the same page.
Table objects have basically three types of callers, and the manual refers to them with these names:
- Script properties
Example: Bulb.State = BulbOn
- Script methods
Example: Kicker.CreateBall()
- Script events
Example: Sub Timer_Expired()

What some people might not know, is Editor properties are also "script properties", so they can be called via script. Most of them are ReadOnly, which means they can't be modified, but it may still be useful to know you can obtain them.

For example, you can use Light.X and Light.Y to obtain the coordinates of a Light, which could be useful to implement some kind of light simple pattern. Coordinates could also be used to calculate the distance between two triggers, and with the help of a timer, you could even get an approximation of the speed of the ball through a lane. Of course where we run BAM flies, but this approach could be enough in some cases.

Another example: You can use DropTarget.BankCount to check how many Event IDs a DropTarget includes, so with this you could make a function that checks every single one independent of how many targets that specific bank has. As you can see, the script properties usually have the same name as in the Editor, without any space or special character.

The default script has only one example usage of this. The variable LastSwitchHit defines the last trigger object that was hit. To check which one it was, it uses its name string, therefore using the editor property Trigger.Name:

Code:
If (LastSwitchHit.Name = "PlungerLaneTrigger") Then
    bBallSaverActive = True
End If

You may not be convinced of its potential yet, but I needed to explain this in order to move on to those properties that can be modified via script.

2. Advanced Kickers​

One of the most important properties you can modify via script is Rotation. Sadly, that's not particularly usable in those objects with a collision box, since it doesn't change its rotation. Hope's not entirely lost though, because some object types can use models with "Per polygon collision" instead. Kickers use that option.

You can modify many Kicker properties in real time.

- Rotation
You can easily make a "Two directional kicker" that launches the ball up or down depending on where it came from (you would check this with two invisible triggers). If the kicker model is symmetrical, the rotation won't be visible, only its effect.

Code:
Dim LastTriggerPressed ' 0: Up, 1: Down

' Update the variable LastTriggerPressed
Sub UpTrigger_Hit()
    LastTriggerPressed = 0
End Sub
Sub DownTrigger_Hit()
    LastTriggerPressed = 1
End Sub

' The Kicker is Hit
Sub DoubleKicker_Hit()
    If (LastTriggerPressed = 0) Then
        ' Look up
        DoubleKicker.Rotation = 0
    Else
        ' Look down
        DoubleKicker.Rotation = 180
    End If
    ' Launch the ball to the current position
    DoubleKicker.SolenoidPulse()
End Sub

You could also make a PinBelt that launches the ball to a random direction, like a very basic magnet release. You will need a MakeRandom function for that:

Code:
' Function to get a random number between two numbers (both included)
Function MakeRandom(ByVal min, ByVal max)
    MakeRandom = CInt(Int((max - min + 1) * Rnd())) + min
End Function

Code:
Sub PinBelt_Hit()
    PinBelt.Rotation = MakeRandom(0, 359)
    PinBelt.SolenoidPulse()
End Sub

- Kicker Type
You can set your Kicker's type (Directional or VerticalUpKicker) via script.

Code:
Kicker.KickerType = 0 ' Directional
Kicker.KickerType = 2 ' Vertical

On this example, a vertical kicker launches the ball to a wire ramp, but on TILT it simply releases it back to the playfield. In order to release it properly, you will have to define its angle on the Editor, even if the model Kicker-Hole-T3 doesn't look rotational. I would recommend making a custom model that makes it clear the kicker is "double".

Code:
Sub VerticalKicker_Hit()
    If (fpTilted = True) Then
        ' On Tilt mode, release the ball back to the playfield
        VerticalKicker.KickerType = 0
        VerticalKicker.Strength = 1
        VerticalKicker.SolenoidPulse()
    Else
        ' By default, launch the ball to the wire
        VerticalKicker.KickerType = 2
        VerticalKicker.Strength = 7
        VerticalKicker.SolenoidPulse()
    End If
End Sub

- Strength
You can set the Kicker's strength via script, from 1 to 9. With this, you could make a Kicker that launches the ball harder the longer you've pressed the Plunger key, for example. Usually you will use this for more basic cases, for example on the previous examples you may want to change the strength when you change directions as well.

- Ball Weight
When you create a ball, you can define its "weight". Without BAM this is a cheap trick, but it kind of works…
The idea behind this has nothing to do with the kicker, nor the ball; what you have to change is the table slope. That change doesn't apply on current balls, but it does apply on new ones. This way, to make a very "light" ball first you would set the Table Slope to 1, create the ball with a Kicker, and set the Table Slope back to its default value again. Note the Table has a Name property as well, just like any other object in the Editor, that's why this is possible.

Code:
' Create a "plastic" ball
Sub CreatePlasticBall()
    ' Store the default table slope
    Dim DefaultSlope : DefaultSlope = NewTable.TableSlope
    ' Set the slope to 3 to create a light ball
    NewTable.TableSlope = 3
    ' (You may want to make the ball a different colour)
    CaptiveKicker.CreateBall
    ' Set the slope to the default value again
    NewTable.TableSlope = DefaultSlope
End Sub

Since this is a bit weird, I would only recommend using it for captive balls, to control their resilience to the player ball. For more complex cases, you could theoretically assign a special BallID to "plastic" balls and modify other object's strength (or effect) based on that, when the ball hits them. Remember, you can set a custom color to the ball as well, to make that more clear… I haven't even tried any of that, though :roll:

Well, I talk way too much. This is all for now, but there's still more to come! ;)
I hope you find this useful!
 
Last edited:
thank you very much for the information, I used two kicker to achieve this. I will definitely use the rotation options in the future.
 
Bally Spectrum used 2 kickers but I used .Rotation when I updated it.
But on that table something else has been bothering me for a while and I think the "plastic ball" trick *might* help me.

Thanks for sharing
 
I'm glad you guys are liking this. Here's another one I've been using a lot.

3. Multi-Colour Lights​

One of the properties you can modify via script is Light colours. With this, you can make LEDs that have multiple colours. The same trick works with any kind of light, including Bumpers and EM Reels.

Not only that, but you can also change the glow radius of a bulb or light, using Light.Radius

There are some things you must be aware of when you use this.

1. Those properties don't update until the light is refreshed, and that happens when it changes its state (lit/unlit). It also takes a few frames to update. That means you can't have a Flasher that changes its hue in a cycle without turning off on each step; it will only work in a "blinking" mode. The same applies to the halo radius, you can't make lights that turn on/off slowly like in the pinball White Water without some more advanced workarounds. I mention some at the end of the post.

2. When you change the LitColour property, the UnlitColour will also update if you have "Autoset Unlit Colour to 33%" enabled. I would recommend turning that off for multi-colour lights, and using a dark gray unlit colour by default.

3. The light colour is defined with a single digit and not 3 like ball colours.
That colour can be defined with the simple formula R + G * 256 + B * 256 * 256, but VBScript has an RGB function already defined that does that automatically.

Code:
Light.LitColour = RGB(255, 128, 32) ' Orange

Round/shapeable lights: You can set multiple lights at the same place, and lit only the desired one. They should all have a completely black unlit colour. To set a custom unlit colour, you use an extra light that when lit has that colour, and hide its halo out of the table.

Invisible bulbs: Halos use a blending mode. That means with six overlapped bulbs you could make a full hue cycle. Those bulbs would be R-255, G-255, B-255, R-128, G-128, B-128. With this you can get any basic colour without changing their LitColour (for example, to get an orange halo you activate R-255 and G-128). Using LitColour, you can reduce that number to three. First, you can reduce it to four by noticing the half-lit halo (*) only appears once in each two colours of the cycle, so it has time to change the LitColour in between:

Code:
R R R * 0 0 0 0 0 * R R
0 * G G G G G * 0 0 0 0
0 0 0 0 0 * B B B B B *

To reduce it further, you can use the first light (1) for R & B in the first cycle and G in the second, and the second light (2) for G in the first and R & B in the second. And just like that, full hue cycle always turned on and with only three bulbs!

Code:
1 1 1 * 0 0 0 0 0 * 2 2 2 2 2 * 0 0 0 0 0 * 1 1
0 * 2 2 2 2 2 * 0 0 0 0 0 * 1 1 1 1 1 * 0 0 0 0
0 0 0 0 0 * 1 1 1 1 1 * 0 0 0 0 0 * 2 2 2 2 2 *

Others: You can recreate lights of any kind and colour with two toys (Lit & Unlit) that will hide/move into place, and an Overlay for the halo. Use the default halo graphic for the Overlay, setting the different colours with Photoshop when required.
If you want examples of this, in my pinball La Castanyera I made Drop target bulbs and Flipper bulbs.

Maybe you don't want to define this by RGB (Red-Green-Blue), but by HSL (Hue-Saturation-Lightness) instead.
In that case, you will need some extra functions to convert between types.

In my pinball La Castanyera, a Flasher blinks changing its hue in Attract Mode.
Here are the functions I made, you can use them if you want.

Code:
Dim FlasherHue, FlasherSat, FlasherLum

Sub GetDefaultFlasherHSL()
    FlasherHue = 0 : FlasherSat = 0 : FlasherLum = 0
    Dim colour : colour = MulticolorFlasher.LitColour
    ' Get RGB from unique value
    Dim r, g, b
    r = colour Mod 256
    g = ((colour - r) / 256) Mod 256
    b = (((colour - r) / 256) - g) / 256
    ' Convert RGB to HSL
    r = r / 256.0 : g = g / 256.0 : b = b / 256.0
    Dim cMax, cMin, cDif, cMean, cSat
    cMax = r : If (g > cMax) Then cMax = g : If (b > cMax) Then cMax = b
    cMin = r : If (g < cMin) Then cMin = g : If (b < cMin) Then cMin = b
    cDif = cMax - cMin : cMean = (cMax + cMin) / 2
    If (cMax = cMin) Then
        FlasherHue = 0
    Elseif (cMax = r) Then
        FlasherHue = CInt(60.0 * ((g - b) / cDif))
    Elseif (cMax = g) Then
        FlasherHue = CInt(60.0 * ((b - r) / cDif + 2))
    Elseif (cMax = b) Then
        FlasherHue = CInt(60.0 * ((r - g) / cDif + 4))
   End If
    If (FlasherHue < 0) Then FlasherHue = FlasherHue + 360
    FlasherLum = CInt(cMean * 256)
    If (cMax = cMin) Then
        cSat = 0
    Elseif (cMean < 0.5) Then
        cSat = cDif / (2 * cMean)
    Else
        cSat = cDif / (2 - 2 * cMean)
    End If
   FlasherSat = CInt(cSat * 256)
End Sub

Function GetColourFromHSL(ByVal hValue, ByVal sValue, ByVal lValue)
    ' Convert HSL to RGB
    Dim r, g, b : r = 0 : g = 0 : b = 0
    Dim h, s, l : h = hValue / 360.0 : s = sValue / 255.0 : l = lValue / 255.0
    If (s = 0) Then
        r = l : g = l : b = l
    Else
        Dim q
        If (l < 0.5) Then
            q = l * (1 + s)
        Else
            q = l + s - l * s
        End If
        Dim m : m = 2.0 * l - q
        r = CInt(HueToRGB(m, q, h + 1.0 / 3) * 256)
        g = CInt(HueToRGB(m, q, h) * 256)
        b = CInt(HueToRGB(m, q, h - 1.0 / 3) * 256)
    End If
    ' Get colour from RGB
    GetColourFromHSL = r + g * 256 + b * (256 * 256)
End Function

Function HueToRGB(ByVal m, ByVal q, ByVal t)
    If (t < 0) Then t = t + 1.0
    If (t > 1) Then t = t - 1.0
    If (t < 1.0 / 6) Then
        HueToRGB = m + (q - m) * 6.0 * t
        Exit Function
    End If
    If (t < 1.0 / 2) Then
        HueToRGB = q
        Exit Function
    End If
    If (t < 2.0 / 3) Then
        HueToRGB = m + (q - m) * (2.0 / 3 - t) * 6.0
        Exit Function
    End If
End Function

And here's how I used them to make the cycle

Code:
Dim DefaultFlasherHue

Sub FuturePinball_BeginPlay()
    ' (...)
    ' Get the default flasher HSL. Only the Hue will change
    GetDefaultFlasherHSL()
    DefaultFlasherHue = FlasherHue
End Sub

Sub SetTableAttractMode() ' Start of multi-color flash effect
    SeqAttractTimer.Enabled = True
    MulticolorFlasher.State = BulbBlink
End Sub

Sub SetTablePlayingMode() ' End of multi-color flash effect
    SeqAttractTimer.Enabled = False
    FlasherHue = DefaultFlasherHue
    MulticolorFlasher.LitColour = GetColourFromHSL(FlasherHue, FlasherSat, FlasherLum)
    MulticolorFlasher.State = BulbOff
End Sub

Sub SeqAttractTimer_Expired() ' Update hue (loop) on Attract mode
    FlasherHue = (FlasherHue + 20) Mod 360
    MulticolorFlasher.LitColour = GetColourFromHSL(FlasherHue, FlasherSat, FlasherLum)
End Sub
 
Last edited:
is there a way to change the texture of a toy? example I would like the C3PO of my playgrounds to be clear or not.
 
can you port the beta-tester .fpt exporter to the latest version of blender 3.3.1 LTS ?
 
@Zobou Only with BAM. In default FP, those Editor properties (texture, model, coordinates, etc.) are ReadOnly and there's no way to update them via script, as far as I know. I guess you could have a hidden Toy under the table with the alternative texture and then swap them, or use some trickery like that, but I don't recommend it.

@fastdraw I believe you can, but I'm not sure. This topic has nothing to do with that, though :|
 
is there a way to change the texture of a toy? example I would like the C3PO of my playgrounds to be clear or not.

There is a BAM code to swap texture. It is easy to use. I use it quite a bit. It is called xBAM.SetTexture. Gimli discusses it here:


You can swap the normal texture on C3PO with the transparent tga. The table mod I did on Space Shuttle uses it to change the text on the apron.
 
Only if something changed in BAM.
slope in script as far as know, can only be changed in scrip via xBAM.PhysicsXML
(I must've written this a few times by now :D )
 
Phones. I've already edited. You're too fast :p
 
Exactly. The table slope can be changed via script, but only affects balls that are still not in play.
Using BAM you can also change that in real time using xBAM.PhysicsXML, or by rotating a Mini-Playfield that covers the whole table.
 
ooooh! since long time we search changing slope without calling xBAM.PhysicsXML!

is "newtable" corresponding to something and need to be changed depend the table?
 
Exactly. The table slope can be changed via script, but only affects balls that are still not in play.
Using BAM you can also change that in real time using xBAM.PhysicsXML, or by rotating a Mini-Playfield that covers the whole table.
"ears perked up at this"
 
ooooh! since long time we search changing slope without calling xBAM.PhysicsXML!

is "newtable" corresponding to something and need to be changed depend the table?

NewTable is the name of the table by default. When you don't have any object selected, the table is selected instead. You can change the name there, and that's the name you use on the script. If you make a generic code that should work on any table, use xBAM.Table instead ;)
 
great! did you have other code like this on your bag that we ignore ? 😅😁🤣
 
I say, WTH?!
Where was all this info before? Surely it can't be info from "last week"...

In any case, i'm glad it pops up now. Better late than never.
 
NewTable is the name of the table by default. When you don't have any object selected, the table is selected instead. You can change the name there, and that's the name you use on the script. If you make a generic code that should work on any table, use xBAM.Table instead ;)
Tested... Work perfect!!! Thank you a lot!

If you have other scriptable setting that possible for Playfield, or also Flipper, tell us 😁
 
Exactly. The table slope can be changed via script, but only affects balls that are still not in play.
Using BAM you can also change that in real time using xBAM.PhysicsXML, or by rotating a Mini-Playfield that covers the whole table.

I am not sure what you mean by only "affects balls that are still not in play".
 
I am not sure what you mean by only "affects balls that are still not in play".
he mean if you change physics setting, they affect the new ball or next ball. Not the current ball.
 
he mean if you change physics setting, they affect the new ball or next ball. Not the current ball.

Thanks. That makes sense. I think the xBAM.PhysicsXML code does affect all the balls on the table.
 
JLou5641 said:
If you have other scriptable setting that possible for Playfield, or also Flipper, tell us 😁

I don't think that's very relevant, since default flippers are very limited compared to what you can do with BAM and FizX. That being said, since you asked, StartAngle and AngleSwing are ReadOnly, but I believe Strength and RubberBounce can be changed via script. I can barely see the difference, though.

Code:
LeftFlipper.RubberBounce = 0 ' Hard
LeftFlipper.RubberBounce = 1 ' Intermediate
LeftFlipper.RubberBounce = 2 ' Soft

On the Playfield, the only other possible writable thing is the parameter TiltWarnings, again not very useful.
Probably not what you were expecting, sorry :|
 
Thanks for information 👍.

I admit if you had something about swing angle or flipper position with script was a dream lol
 
Forum activity
Help Users
You can interact with the ChatGPT Bot in any Chat Room and there is a dedicated room. The command is /ai followed by a space and then your ? or inquiry.
ie: /ai What is a EM Pinball Machine?
  • No one is chatting at the moment.
      Chat Bot Mibs Chat Bot Mibs: Mauma is our newest member. Welcome!
      Back
      Top