Monster Bash¶
The Monster Bash Skitso Mod was a landmark VPW collaborative project, developed from December 2020 to February 2022 with 30+ release candidates. Originally a "Skitso mod" of randr/Unclewilly's table, it became the first table released under the VPW brand. Key contributors: Skitso (visuals/project lead), rothbauerw (physics/sounds), iaakki (scripting/flasher code), sixtoe (VR integration), bord1947 (3D mesh work), tomate80 (wire ramp textures), and many others.
Build Notes¶
Playfield Mesh and Physics Collision¶
Bord1947 provided a playfield_mesh.obj and a separate phys_plywood.obj -- a physics-only collidable mesh that gives plywood sides of playfield holes a collision surface. The physics mesh should NOT be made visible; it is purely for ball collision.
PWM/Lampz Upgrade Path¶
MB uses older JP (Jordy Pijpers) fading code for lamp control. Upgrading to PWM requires converting from JP fading to either Lampz (intermediate step) or directly to PWM. Iaakki had a macro to generate Lampz mass-assignments from JP fading code. The table's "epic light shows" make PWM particularly worthwhile but the conversion is non-trivial.
VPX Version Requirements¶
UpdateMaterial function requires VPX 10.6.1 or newer. Also recommended: SAMBuild r5240.
3D & Art¶
Skitso's Lighting Methodology¶
- Use normal playfield (no artificial darkening)
- Achieve mood with day/night slider, environmental image, and carefully crafted LUT
- Go through GI lighting one by one, comparing with PAPA videos for reference on color temperature
- Use Pinside/reference images for light obstruction, shadow behavior, and light transfer through plastics
- Go through inserts last
Key philosophy: "To have a virtual pinball machine look good is not to make one element more realistic -- it's about the whole big picture looking cohesive."
Insert Lighting Technique¶
Skitso uses two VPX light objects per insert (for inserts without defined edges like monster heads) -- one for the insert itself and a second to smooth edges and prevent harsh/sharp appearance. This technique requires playfield reflections to be enabled in VPX global settings; disabling PF reflections causes dark squares around the inserts.
LUT (Color Grading) Philosophy¶
The table uses fading LUTs (multiple ColorGrade images) that change with GI level for darker ambient when lights go out:
If Step >= 7 Then
Table1.ColorGradeImage = "ColorGrade_8"
Else
Table1.ColorGradeImage = "ColorGrade_" & (step+1)
End If
Skitso strongly opposed including a LUT selector, preferring a single curated visual vision.
Wire Ramp Texture Improvements¶
Tomate80 improved wire ramp textures with better contrast between bright and dark parts. New textures added ~6MB to file size but required no model changes -- just better texture rendering with improved lighting/shadows baked in.
Tesla Coil Dome Replacement¶
Flupper suggested stacking two half-ball flasher domes for the Tesla coil globes. The final implementation uses 4 half-domes (2 per globe) across 4 depth biases with 8 total primitives, using a custom purple texture.
Scripting¶
FadeDisableLighting for Insert Tray Brightness¶
Sub FadeDisableLighting(nr, a, alvl)
Select Case FadingState(nr)
Case 4
a.UserValue = a.UserValue - 0.25
If a.UserValue < 0 Then a.UserValue = 0
a.BlendDisableLighting = alvl * a.UserValue
Case 5
a.UserValue = a.UserValue + 0.5
If a.UserValue > 1 Then a.UserValue = 1
a.BlendDisableLighting = alvl * a.UserValue
End Select
End Sub
Flupper Flasher Dome Implementation¶
Flupper flasher domes use multiple components: base primitive, lit primitive, flasher object, and light object. Key control: objlit(nr).BlendDisableLighting = 10 * ObjLevel(nr)^2. The ^x exponent controls fading speed -- higher values = faster fade. Different exponents on different components create natural-looking fading:
objflasher(nr).opacity = 1000 * FlasherFlareIntensity * sol19_3lvl^2.5
objlight(nr).IntensityScale = 1 * FlasherLightIntensity * sol19_3lvl^3
objbase(nr).BlendDisableLighting = FlasherOffBrightness + 30 * sol19_3lvl^2 + 0.1
objlit(nr).BlendDisableLighting = 15 * Sol19_3lvl^0.9 + 0.1
Objects nearest the light origin should fade slowest (lowest exponent).
Modulated Solenoid Flashers¶
Frankenstein flashers were switched from SetModLamp to SolModCallback for modulated output. SetModLamp always starts at max (255) and can't pulse. With SolModCallback, output follows actual solenoid ROM values -- most hits are 150-160, reaching max only at "It's Alive" and Jackpots.
FadeModLamp vs FadeLamp Termination Rules¶
In the JP fading system, lamp routines with "Mod" suffix (NFadeLm, Flashm, FadeDisableLightingM) do NOT terminate the fading cycle. The last routine in a sequence MUST use the non-Mod version:
' Correct order:
FadeDisableLighting 81, cfeatures2d, 0.85
Flash 81, l81ref ' This terminates the fade
Dynamic Ball Shadows¶
Array-based implementation performs better than collections (especially in VR):
- Max 2 simultaneous shadow sources recommended
- Limit DynamicSources to lights that actually cast visible shadows
- Shadow intensity: 0.95-0.98 range
- When adding GI bulbs near each other, only include 1-2 to prevent flickering
- Dynamic shadows have the biggest performance impact of any feature -- first thing to disable for performance
VR Mode Detection¶
' Wrong (logic error - always true):
If VRRoom = 0 or DesktopMode = 0 Then
' Correct - show in cabinet only:
If VRRoom <> 0 or DesktopMode Then
' VR or Desktop code
Else
' Cabinet-only code
End If
VR can run from cabinet mode, so don't assume VR = desktop.
Flasher Fading Performance Optimization¶
Optimize by adjusting timer interval and fade equation:
- Original: timer=30, equation
0.9 * objlevel= 23 fading steps - Optimized: timer=35, equation
0.8 * objlevel= 14 fading steps - Fewer steps = fewer semi-transparent texture overlaps = better GPU performance
Key insight: overlapping semi-transparent textures are the main performance bottleneck, not script execution.
Troubleshooting¶
VR Swimming Lights¶
Semi-transparent objects set to static rendering cause "swimming" lights when you move your head in VR. Fix: untick "Static Rendering" (set to Active). For Monster Bash, setting the playfield opacity to 1.0 instead of 0.999 and using a cutout for the Creature area resolved the issue.
Dracula Mechanic Array Bounds Error¶
When the Dracula mechanic sends invalid position values, add bounds checking:
Target Bouncer Causing Ball Jumps¶
Target bouncer gives z-velocity on first hit, then a second target amplifies it. Fix: add "ceiling" walls above target areas to prevent balls from jumping too high.
Stuck Balls from Overlapping Geometry¶
Ramps made of walls (collidable) AND a primitive mesh create a "hill" at ramp exits. Fix: modify the primitive to match the ramp exit shape and delete the redundant walls.
VPX 10.8 Normal Map Rendering Regression¶
VPX 10.8 broke rendering with funky textures on Frankenstein and other objects. Root causes: normal mapping issues in both DirectX and OpenGL, and reliance on a long-standing VPX bug where texture transparency was ignored if material opacity was 1.0. Niwak pushed an automatic fix to VPX that corrects old tables on load.
Pop Bumper GI Washout¶
Pop bumper area appeared washed out in orange light. User fix: find rollover lane guide lamps in GITopRight collection, raise falloff power from 4 to 10, lower falloff range from 150 to 50.
Collidable Decorative Primitives¶
Small decorative primitives (nuts around Frank, slingshot nuts) were accidentally set as collidable. Always audit small decorative prims to ensure they're non-collidable.
Game Knowledge¶
Phantom Flip Feature¶
Monster Bash's Phantom Flip uses eddy sensors under the playfield above each flipper. The ROM calculates ball speed from inlane switch to sensor timing. Fresh NVRam = no phantom flips until enough data collected. On real machines, this feature is notoriously unreliable. Tournament mode disables phantom flips. Can be disabled in ROM settings (F1 menu).
Best Practices¶
Table Release Process¶
- 90-day "bro code" waiting period before mods are published
- Modders must credit original team and link to original file
- VPU Patching System (by Dazz) creates small diff patches requiring the original download
- Table went through RC1-RC10 testing cycle with dedicated testers before release
POV Configuration¶
- Z-scale should always be 1
- Maintain perspective for POV-dependent lighting/model tricks
- Minimize egg-shaped balls (X:Y scale near 1:1)
- Some tables have POV-dependent flasher effects that break with altered POV
VR Performance (Order of Impact)¶
- Collidable prims (most impact)
- Big/complex textures
- Complex/high-poly prims in viewport
- Semi-transparent texture overlaps (flashers)
- Everything renders twice (once per eye)
Set VR far plane to 2000-3000 to limit render distance.
Display Calibration¶
Many complaints about table darkness stem from uncalibrated displays. Old/faded LCDs, low brightness settings, and incorrect GPU driver color settings (limited vs full range) significantly affect perceived brightness.
Resources¶
- PAPA tutorial video (physics reference): Monster Bash at PAPA HQ
- VPU Patching System: VPU Patcher
- Rubberizer script adds negligible performance overhead and doesn't affect ball spin