Skip to content

Transporter: The Rescue

A comprehensive VPW build of this late-80s Bally System 11 table, featuring primitive insert work adapted from Radical, nFozzy physics tuned for the era, rendered GI lighting, beveled plastics, and extensive troubleshooting of ball shadow and performance issues on a multi-level playfield.

Build Guide

Sys11 Primitive Insert Setup

For System 11 tables, copy primitive inserts from Radical as the best reference (iaakki, benji084). Each insert needs paired primitives named p{N} and p{N}off (matching light L{N}). Steps:

  1. Cut holes in the playfield where insert images are
  2. Copy insert materials and primitives from the reference table
  3. Rename to match light numbers
  4. The insert text layer goes on a separate PNG
  5. Both ON and OFF primitives must have matching X/Y coordinates -- align them in pairs before renaming

Tip

Lock primitives after positioning to prevent accidental movement.

NF Lampz for Insert Lighting

To make primitive inserts light up with proper fading instead of binary on/off, use NF Lampz instead of legacy vpmMapLights (iaakki). Each insert needs two MassAssign lines:

Lampz.MassAssign(6) = l6
Lampz.Callback(6) = "DisableLighting p6, 10,"

The first line maps the VPX light; the second controls the primitive's DisableLighting (DL). The last value (10) controls brightness per-insert. Adjust via msgbox debugging to find correct DL values. Keep original VPX lights at intensity 0 for ball reflections.

Ambient Occlusion Layer

Two AO approaches (benji084, bord1947):

  1. Bake AO into playfield texture -- simpler but less control
  2. Separate VPX flasher layer -- more control over darkness/intensity, allows user-adjustable shadowing via table options (like Cyclone/Hurricane tables)

When using the separate AO flasher approach, ensure the Z depth is correct to avoid ball shadow conflicts. AO holes must match insert cutout holes to prevent shadows rendering over inserts.

80s Era nFozzy Flipper Tuning

Flipper physics for 1980s/early 90s tables differ from modern (iaakki). Flip power should be 2000-2600 (vs ~3300 for 90s+). Reference values:

EOSTnew = 1, EOSAnew = 1, EOSRampup = 0
SOSRampup = 6 (recommended, default 2.5)
LiveCatch = 16, LiveElasticity = 0.45
SOSEM = 0.815, EOSReturn = 0.035
Slingshot: threshold 2, force 5, friction 0.8
Flip elasticity: 0.84 (0.88 was too bouncy)

Tap Pass / FlipperCoilRampupMode

FlipperCoilRampupMode script option controls tap pass behavior (iaakki):

Mode SOSRampup Behavior
0 2.5 Original, no tap passes
1 6 Balanced (recommended)
2 8.5 Easy passes

Higher SOSRampup means slower flipper acceleration, giving a wider window for tiny flicks. Tap passes require fast-return buttons (leaf switches or micro-leaf). Standard microswitches may be too slow. Pinscape with leaf switches works best.

nFozzy Physics Materials

Updated physics materials use z_col_... naming prefix (benji084). Key change: posts and pegs friction changed from 0.6 to 0.9 (significant). Distinctions:

  • Posts: have rubber bands wrapped around them (or are larger standalone rubbers)
  • Pegs: tiny standalone pieces
  • Sleeves: a third category

The slingshot rubber band at the "elbow" should be divided into two sections with a post rubber primitive between them for accurate collision. Materials need assignment to all objects (ramps, walls, etc.), not just rubbers.

Upper Playfield Dimensions

The upper playfield was ~40 VP units thick when real life should be about 24 VP units (bord1947, sixtoe). The bottom position was correct but the top surface was too high. The team chose to raise the bottom by 15 VP units rather than lower everything on top (which would have required moving ramps, ship, mini playfield, and more). For VR accuracy, lowering everything would be better, but the labor cost was too high.

Rendered GI Lighting Layer

GI lighting and AO were rendered in Blender as a playfield flasher layer (bord1947). The flasher toggles between GI on/off states with opacity fading. Implementation: set the GI flasher .visible and .opacity to match GI state using a fading timer for smooth transitions. Drop all playfield-level GI bulbs below the playfield surface so the ball and plastics still receive VP light for reflections while the rendered flasher handles visual GI appearance.

Dynamic Shadows for Multi-Level Tables

Dynamic shadow code triggers only above Z=30, ensuring it works regardless of upper playfield height adjustments (wylte). When the ball is on plastic ramps, show the ambient primitive on the playfield below. Added flasher shadows for ramp traversal. The shadow logic uses Sliderpoint's upper playfield quadrant technique to determine which shadow region to activate.

Funnel/Spinner Fin Geometry

The real Transporter funnel has protruding fins in the lower section that catch the ball when it slows down (lumigado, iaakki). The VPX version had fins in a collidable primitive (Primitive8, layer 2) but they were too low to affect the ball. Fix: increase fin height so the ball contacts them sooner during deceleration. This fix was later applied to Radical, which had an amplified version of the same ball-lingering problem.

Flipper Start Angle Alignment

Setting both flipper start angles from 125 to 126 degrees fixed the center post pass and better aligned with Pinside reference photos (iaakki). The 1-degree change is enough to fix ball routing -- at 125, medium-speed balls hit the post but deflect into the opposite flipper tip. Always compare flipper positions against real machine photos.

POV Setup: 1:1 Scaling

Three POV philosophies for cabinet players (cyberpez, bord1947, apophis79):

  1. Pure 1:1 (x=1, y=1, z=1) with z-offset to fill screen -- preserves proportions, shows relative table sizes
  2. Proportional X/Y scaling -- maintains aspect ratio
  3. Independent X scaling up to 10-20% wider with apron crop -- fills screen but adds some distortion

Tip

Place a quarter on the playfield glass as a size reference for getting circles round. The quarter calibration method accounts for glass distortion.

VR Backglass Flashers

leojreimroc implemented VR backglass flashers using images created by iaakki from his real machine. Backglass number flasher colors can vary between machines (LED vs incandescent, replaced by previous owners). Yellow flashers may be more visible than red in VR despite red being more authentic. Version 1.09 became the final public release with this backglass work.

Ramp Object DL Limitation

VPX ramp objects do not support BlendDisableLighting, preventing them from responding to GI state changes via script (iaakki). The UpdateMaterial workaround only works in F6 (editor preview), not F5 (play mode). Solution: export ramps from VPX, import into Blender, convert to primitives (triangulate + UV map), then re-import as primitive objects which do support BlendDisableLighting.

GI Timing Bug

Extra ball GI flickering had a timing bug: a 5-second reset timer caused incorrect counting due to a 4-second cap in the underlying logic (iaakki). Fix: reduce the reset timer from 5 seconds to 3.5 seconds. Diagnosed by counting from PinMAME traces. This type of GI timing issue is common with solenoid-controlled GI on late-80s Bally/Williams tables.

Scripting

GI Relay Solenoid Sound Faking

Some tables (including Transporter and BBBB) use GI relay solenoids that PinMAME cannot send events for properly (iaakki). When the game runs, the solenoid spams events too fast, making click sounds unintelligible. Fix: fake the GI relay clicks in the script for specific events rather than relying on PinMAME. The BBBB table has a reference implementation.

Sound Randomization One-Liner

Instead of verbose Select Case blocks for random sound selection, use a one-liner (benji084):

Sub RandomSoundBallRelease(drainswitch)
    PlaySoundAtLevelStatic SoundFX("BallRelease" & Int(Rnd*7)+1), DOFContactors), BallReleaseSoundLevel, drainswitch
End Sub

Requires sound files named with sequential numeric suffixes (e.g., BallRelease1 through BallRelease7). All Fleep sound files were renamed to have numerical endings for this shorthand pattern.

Drop Target Implementation

Drop targets use rothbauerw's method (apophis79, bord1947). Key tuning: DT elasticity falloff needs adjusting to prevent springy feel (initial version felt like tennis). The implementation included: drop target code, shadows, tweaked BallLockFlasher intensity, RDampen timer fix, CorTracker code update, vely<0 patch to Rubberizer, and AudioFade/AudioPan crash prevention.

Ball Reflection Colors

Insert lights must have correct colors set for ball reflections to work (iaakki). If light color is black (default when copying), no reflection appears on the ball. After placing primitive inserts, go back and set each VPX light's color to match the actual insert color. GI light color also affects ball reflections -- incandescent white is usually more accurate than yellow/orange.

Rubberizer Comparison

Rubberizer 1 reverses spin only on low velocities (matches stiff real-world flip rubbers). Rubberizer 2 reverses spin at higher velocities too and uses randomization (iaakki, pinstratsdan). iaakki found Rubberizer 2 made the ball feel unpredictable on Transporter. Recommendation: default to Rubberizer 1 for most tables. Preference is table-dependent.

3D & Art

Insert Edge Anti-Aliasing

VPX cannot show alpha blending on playfield image holes, causing jagged edges around inserts (iaakki). Fix: create 5-pixel-wide edge rings from the playfield texture around each insert hole. Place these on the insert text flasher/ramp layer. Enlarge playfield holes by 2 pixels so the edge ring overlaps and masks the jagged pixels. The flasher/ramp layer CAN show alpha blending, unlike the main playfield surface.

Playfield Texture Sizing

Target 4K resolution (2160 pixels wide) for VPX release rather than source resolution (flupper1). Downsizing to 4K usually gives BETTER sharpness in VPX due to texture filtering, while significantly reducing file size. For plastics and toys, texture size should match 4K VPX resolution proportionally.

Flupper Ramp Rendering

Flupper's ramp creation process (flupper1, benji084): model ramps in Blender matching physical geometry, UV unwrap, render baked textures. Import into VPX as primitives. Leave old VPX ramps in place for physics -- the rendered primitives are visual only. Clear/white plastic with VPX material coloring allows easy color options (e.g., white ramp + red VPX material = red ramp).

Beveled Plastics Baking

Plastics baking workflow (benji084, embee1979):

  1. Prepare a 1:1 canvas PNG with all plastics laid out, transparency removed
  2. Model in Blender, tracing outlines from reference
  3. Bake refraction/bevel effect
  4. Export as OBJ files
  5. Import into VPX with correct position values
  6. Assign materials for light pickup on edges

Note

Refraction effect can cause text smearing on plastic edges. Reduce refraction on text-heavy areas.

GI Light Color

Yellow GI lights make everything look "sickly green" (bord1947, iaakki). Use incandescent white or daylight color instead. When using rendered GI flasher layers, the VPX GI bulbs should be dropped below the playfield (for ball reflections only) while the rendered layer handles visual appearance.

Troubleshooting

Ball Shadow Z-Order on Multi-Level Playfields

Ball shadow code that adjusts shadow Z position can cause inverted shadows (bright instead of dark) when the shadow primitive Z conflicts with flipper shadows (iaakki). Fix: ball shadow Z should be calculated from actual ball position to automatically adjust for the upper playfield. Set flipper shadow Z at 0.12 and let ball shadows settle at ~0.05-0.08. Flipper shadows must be higher Z than ball shadows.

RDampen Timer Performance

Setting the RDampen timer interval to 1ms caused FPS to cap at 68hz on a 144hz display (iaakki, apophis79). Script execution consumed over 30% of frame time. Fix: move cor.update under the game timer and set RDampen timer to 10ms instead of 1ms. This raised FPS from 68 to 93 (with SCSP) and 136 (without SCSP). The CPU is the bottleneck for script execution.

Missing Fleep Rubber_4 Sound

Some Fleep sound packages are missing the Rubber_4 sound file (apophis79, benji084). The official tutorial link includes it, but older downloads may not. Workaround: duplicate Rubber_3 and rename to Rubber_4. Always verify the Fleep package against the official tutorial download.

VPX Image Manager Lost Off-Screen

If the VPX Image Manager window opens off-screen, fix via Windows Registry (iaakki, sixtoe): navigate to Computer\HKEY_CURRENT_USER\SOFTWARE\Visual Pinball\VP10\Editor and set ImageMngPosX and ImageMngPosY to 100. Same fix applies to other VPX editor windows.

DMD Hidden Behind VPX

In exclusive fullscreen mode, the PinMAME DMD window can get drawn behind VPX (iaakki). Root cause in this table: someone had added Controller.Hidden = 1 in the script. Fix: remove or set Controller.Hidden = 0. Note: there's a known VPX/PinMAME bug where the DMD can't be raised on top after exiting and relaunching within the same VPX session.

Stuck Ball Prevention

Ball stuck between main ramp and bumper area due to a path that shouldn't be physically possible (iaakki, sixtoe). Fix: add collidable walls blocking impossible ball paths. As sixtoe noted, adding walls that never existed on real machines is sometimes necessary -- real machines also get stuck balls, and there's a whole aftermarket mod scene for preventing ball traps.

Game Knowledge

Double Leaf Switch Flippers

The real Transporter has double leaf switches on the right side, allowing the player to cradle balls on the bottom right flipper while independently actuating the top right flipper (apophis79). VPX supports this behavior but the table script must code for it. PAPA reference video shows the technique being used to hold two balls while shooting the transporter ramp with the upper flipper.

Best Practices

Collaboration Workflow

VPW collaboration practices for binary VPX files (sixtoe, agenteighty6, embee1979):

  • Put a changelog at the top of the script with version number and author
  • Announce "I've got it for the next X hours" to prevent conflicts
  • Art/image work and scripting can often proceed in parallel
  • Fiddly editor changes (object positions, primitives) are the most conflict-prone
  • Merging separate contributions requires careful attention