Skip to content

Maverick

Maverick (Data East 1994) is a ground-up VPW table build (not a mod) featuring a photo-stitched playfield, custom flipper models, a trigonometry-driven paddle wheel mechanism, RTX dynamic ball shadows, rotation-aware drop target collision code (InRotRect), and a ROM bug workaround for ball lock release. Built by antisect with contributions from the VPW team over approximately 3 months of active development.

Build Notes

Widebody vs Standard Dimensions

Maverick had a widebody prototype (25" x 51.75") but production was squeezed to standard cabinet (20.25" x 46"). The VPW build used standard dimensions confirmed by photos and real machine measurements. Getting accurate dimensions early is critical for a ground-up build -- everything else is built relative to the playfield.

Playfield Stitch and Twist Correction

EBisLit stitched the playfield from high-res photos of a depopulated machine. The stitch had a twist/distortion that apophis79 corrected using Photoshop's distort tools. When correcting distortion, verify against real table element positions before committing to cleanup work.

Lane Guides Should Use VPX Walls

Lane guides should be made with VPX walls rather than collidable primitives. Collidable prims have intermittent collision issues that can cause ball sticking. Same principle applies to ramps -- using VPX walls makes it easier to adjust friction values per section later.

Image Size Optimization

Oversized textures waste texture memory and can look worse due to VPX resizing. Inlane textures at 4K when inlanes are only 1/8 of table length can be reduced to 2K (4x smaller, 25MB to 5MB) with zero visible quality loss. Always evaluate actual screen area coverage when choosing texture resolution.

VPX 10.7 Brightness Changes

VPX 10.7 made tables noticeably brighter at default settings compared to 10.6. Changes related to light transmission filter radius, revamped bloom filter, and fixed insert lights when playfield reflections disabled. Converting LUT images to WebP format may subtly affect brightness/color -- keep LUT images as PNG.

Trough/Lock System Architecture

Maverick uses a two-solenoid trough system: SolCallBack(1) for Lockout and SolCallBack(2) for Ball Release/Eject. Implementation uses two cvpmBallStack objects -- bsTrough for the main stack and bsTroughKick as a saucer for ejection. Different from the typical Data East double-kicker trough on tables like Batman Forever and Baywatch.

VR Room and Cabinet Setup

Cabinet artwork assembled from found photos with Photoshop cleanup and color correction. Maverick uses the Sega 192-dot wide DMD (same as Baywatch, Batman Forever), larger than standard. Players with real DMD hardware can't display these wider-format DMDs.

Version Progression

WIP-17 through WIP-39 by antisect (physics, sounds, table elements). After antisect departed, sixtoe took control (v40+): VR room, script cleanup, image optimization. The table went from 190MB to 100MB through image optimization. Released at v1.0, updated through v1.3.

Scripting

Paddle Wheel Ball Rotation

The Maverick paddle wheel that rotates balls uses trigonometric math (sin/cos functions) rather than primitive bounding box collision. This approach is necessary because the wheel geometry doesn't fit standard collision detection. The rotation calculates ball position relative to wheel center to simulate the physical motion of balls being carried by the wheel mechanism.

Ball Lock ROM Bug Workaround

Maverick has a ROM bug where pressing start too quickly after game over (before locked balls return to trough) permanently traps balls in the lock. The workaround intercepts the start button in vpmKeyDown:

If (vlLock.Balls<>0) then LockRelease else .Switch(swStartButton) = True

This breaks buy-in but prevents the ball trap. The final fix used the keydown handler approach without bypassing de.vbs.

Detecting Game Over State

VPX has no built-in way to detect if a ROM game is over. Methods explored: Game Over lamp (Maverick doesn't have one), start button lamp (unreliable), flipper dead state (unreliable), GI state (unreliable), ball count in trough (most reliable for Maverick). For the Maverick workaround, checking lock state in vpmKeyDown proved sufficient.

Drop Target InRotRect Fix

Drop targets resetting could launch balls into the air. Root cause: the InRect collision check didn't account for target rotation or ball Z position. The fix uses a rotation-aware rectangle check:

Function InRotRect(ballx,bally,px,py,angle,ax,ay,bx,by,cx,cy,dx,dy)
    Dim rax,ray,rbx,rby,rcx,rcy,rdx,rdy
    Dim rotxy
    rotxy = RotPoint(ax,ay,angle)
    rax = rotxy(0)+px : ray = rotxy(1)+py
    rotxy = RotPoint(bx,by,angle)
    rbx = rotxy(0)+px : rby = rotxy(1)+py
    rotxy = RotPoint(cx,cy,angle)
    rcx = rotxy(0)+px : rcy = rotxy(1)+py
    rotxy = RotPoint(dx,dy,angle)
    rdx = rotxy(0)+px : rdy = rotxy(1)+py
    InRotRect = InRect(ballx,bally,rax,ray,rbx,rby,rcx,rcy,rdx,rdy)
End Function

Function RotPoint(x,y,angle)
    dim rx, ry
    rx = x*dCos(angle) - y*dSin(angle)
    ry = x*dSin(angle) + y*dCos(angle)
    RotPoint = Array(rx,ry)
End Function

Full check with Z-height: If InRotRect(BOT(b).x,BOT(b).y,prim.x,prim.y,prim.rotz,-25,-10,25,-10,25,25,-25,25) and BOT(b).z < prim.z+DTDropUnits+25 Then. Also reduce velz from 20 to ~10. Key insight: rotate points around the target center (px,py), not around (0,0). This became standard drop target scripting.

RTX Dynamic Ball Shadow System

Wylte's RTX dynamic ball shadow code uses primitives (not flashers, which can't be resized) that move relative to the ball and light positions. Ideal system: normal ambient shadow (always present) + 2-4 additional shadows from GI bulbs that stretch and rotate based on ball position relative to each bulb.

Shadow design considerations:

  • Shadows should appear next to the ball, not under it
  • Shadow length changes with distance to bulb
  • GI shadows should fade when GI goes off
  • Performance concern: with 5-ball multiball and 4 shadows per ball = 20 shadow primitives
  • Optimization: only show shadows on 2-3 balls closest to player
  • Material opacity (UpdateMaterial command) controls shadow fade-out with distance

Kickback Autocycling Bug Fix

The kickback was autocycling (firing repeatedly). Fix involved cleaning up old/redundant script: old VP9-era code, duplicated keyup/keydown routines, stuff now handled by de.vbs being redefined in the table script. About 100 lines of dead code were removed. Tables built incrementally often have these conflicts.

Rubberizer 1 vs 2 Comparison

Rubberizer parameter meanings: Blue values = bounce magnitude (upper for hard touches, lower for micro-bounces). Red values = spin change for hard bounce -- rubberizer 2 (apophis version) reverses spin on hard touches too, which may be unrealistic. Green values = micro-bounce spin. The difference between rubberizer on and off should be subtle: 1-2 extra bounces per flip. Slow tables like Maverick are more sensitive to rubberizer settings because the ball takes longer to settle.

3D & Art

Plastic Ramp Modeling and Baking

Tomate80 modeled the plastic ramp in Blender with excellent polygon flow. The ramp texture baking process uses Flupper1's tutorial: export table from VPX to Blender, apply lattice, UV project from view (press numpad 0 first), render. 100 samples is sufficient -- the denoiser handles the rest.

Common mistakes when following the tutorial: (1) forgetting to divide camera X/Y/Z by 1000, (2) not applying lattice modifier to playfield meshes before UV projection, (3) forgetting to use "Project from View" with numpad 0.

Advanced Ramp Rendering

Flupper1's advanced tips: (1) Clean imported VPX ramp mesh -- triangles should be converted to quads and double vertices removed. (2) Rotate environment images for balanced reflection. (3) Use Multiply texture x4 for vertex colors in ramp material for stronger refraction. (4) Disable "affect alpha" for specular shader and enable "visible env refraction" for screenshot image in world nodes (undocumented tip). (5) Split UV into 4 islands for better texture coverage.

Ramp Depth Property

Setting ramp depth to -100000 in VPX makes it render transparent to everything underneath. Critical for VR where depth ordering of overlapping elements is essential.

Wire Ramps from Future Pinball

Wire ramps for Maverick were built in Future Pinball and then imported into VPX. Future Pinball has better tools for creating wire ramp geometry that can then be exported and used as primitives.

Custom Flipper Models

Tomate80 created custom flipper models with spade and heart logos matching the Maverick theme. Custom flipper primitives replace the standard VPX flipper meshes for visual accuracy while keeping the same flipper physics underneath.

Spotlight Implementation

Spotlights in VPX have no good native implementation. Best approach: (1) Use angled fading transparent flasher as the light cone. (2) Color should not be pure white -- center white, fading to yellowish at edges. (3) Add glow with a VPX flasher object. (4) Add side wall reflections with flasher. (5) Connect illuminated objects to DisableLighting (DL). (6) Never use light cones -- they look terrible, especially in VR. (7) Spots are nearly always connected to GI.

WebP Image Format

WebP format (VPX 10.7+) reduces table file size roughly by half compared to PNG with no visible quality loss. Playfield image went from 18MB PNG to 12MB WebP. Overall table dropped from ~190MB to ~100MB. Lossless WebP is safe for table assets. LUT images should remain PNG as WebP conversion may subtly affect color mapping.

Troubleshooting

POV Settings Causing Ball Loss

Modified POV settings can cause rare ball interaction bugs. POV changes (especially Z-scale) affect collision geometry. When debugging rare ball behavior, always check if the player modified their POV, particularly Z-scale values.

BallCor/Division by Zero Error

Tables using nFozzy physics sometimes throw "Division by zero" or "BallCor collision" errors on launch. This relates to the RDampen timer and captive ball initialization. The solution varies per table but typically involves proper initialization ordering. The issue appeared across multiple tables in 10.7 betas, never in 10.6.

VPX 10.7 Script Compatibility

VPX 10.7 introduced several compatibility issues: (1) LoadController is an internal function -- calling it directly from table scripts broke in 10.7. (2) Different 10.7 beta builds behaved differently. (3) MP3 format for table sound samples was untested -- converting to WAV fixed sound issues. (4) The VPX 10.7 built-in Find function was case-sensitive without indication.

SSF Positional Audio Not Working

Some Fleep sound calls used basic PlaySound instead of positional PlaySound. MP3 format for table samples also caused issues on some configurations -- converting back to WAV resolved problems.

Game Knowledge

Playing Characteristics

Maverick plays differently from most tables: it's a very flat/low-angle table by design (accurate to real machine), ball speed is slower than typical, and rubberizer effects are more pronounced. Lauren Belle mode is the key scoring opportunity with "explosive scoring moments."

Lauren Belle Mode ROM Bug

During Lauren Belle mode, locked balls can release unexpectedly and add an extra ball to play. This is a confirmed ROM bug present on real Maverick machines, documented on Pinside and verified with video evidence. The VPW team left it as-is since it accurately represents the real machine.

Poker Championship Mode

The Poker Championship is a 4-ball multiball mode with a 30-second ball saver. Players must manually plunge each ball -- the game won't auto-serve new balls. If you don't launch within the ball saver period, you miss out on the full 4-ball multiball.

Resources

  • ITC Cheltenham Condensed Ultra font matches Maverick playfield insert text (free at download-free-fonts.com)
  • Flupper1's ramp baking tutorial for Blender-to-VPX ramp textures
  • Wire ramp rolling sound loops adapted from JD implementation
  • RampRoll sound triggers placed at ramp entry/exit points