Indiana Jones (Williams)¶
Scripting and 3D art powerhouse featuring advanced insert techniques, GI fading systems, nFozzy physics integration, and extensive troubleshooting of VPX rendering issues.
Build Notes¶
Insert Primitive Construction¶
VPW's insert system uses two primitives per insert for realistic depth:
- OFF primitive (top layer): unlit texture with transmission and blendDisableLighting enabled
- ON primitive (beneath): lit texture
- Small VPX light positioned between trays at z≈-3, very low intensity (0.2-0.4) for subtle haze and ball reflection
This creates realistic depth when viewed from angles, especially in VR. Later iterations expanded to 3-5 elements per insert for additional realism.
Rotating inserts (Path of Adventure mechanism) need special handling: use RotZ (not RotY) and ensure rotation center matches the original mesh position. Set primitives to same position as original meshes, then use TransXYZ values to visually offset.
Insert Lighting Tuning¶
Real-time insert tuning workflow:
- Start game, open editor (F6)
- Type
p17.blenddisablelighting=70and Enter - Adjust value, Enter again to see changes
- When satisfied, add value to script in
Lampz.Callbackline
Key settings: - Bulb intensity: 5-10 (very low) - BlendDisableLighting: 40-200 typical range for inserts - Most illumination comes from DL, not bulb intensity - Overlay lamp intensity: 0.2-0.4
Scripting¶
nFozzy Lighting Integration¶
Getting ROM-controlled GI working with nFozzy lighting:
- Identify 5 GI channels (0-4) following FunHouse logic pattern
- Each channel gets its own VPX collection
- Five test lights correspond to channels
- GI verified through ROM diagnostic test mode (8-step dimming)
- GI channel IDs must not overlap lamp IDs
Solenoid-Controlled Lamps¶
When solenoid numbers overlap lamp IDs:
SolCallback(17) = "ModLampz.SetLamp 117,"
Lampz.MassAssign(117) = Light117
Lampz.Callback(117) = "DisableLighting p117, 80,"
Division-by-Zero Fix¶
The nFozzy Dampen function can crash when cor.ballvel() returns zero:
BallVelBack = cor.ballvel(aBall.id)
if BallVelBack = 0 Then BallVelBack = BallVelBack + 0.000000000000000001
RealCOR = BallSpeed(aBall) / BallVelBack
GI Material Fading¶
Using UpdateMaterial for smooth, stepless GI fading:
Parameters: wrapLighting, roughness, glossyImageLerp, thickness, edge, edgeAlpha, opacity, base color, glossy, clearcoat, isMetal, opacityActive, elasticity, elasticityFalloff, friction, scatterAngle.
Baked Flasher Reflections¶
System for flasher reflections on primitives:
- On flash trigger: swap OFF prim images to flash texture
- Fade ON prim material opacity from full to zero (reverse: Case 0=full, Case 3=zero)
- Simultaneously fade dome DL, playfield overlay flasher opacity, and bloom
- When flash level < 0: revert OFF prim images to gi_off texture
Dynamic LUT Adjustment¶
Indy dynamically adjusts color grade based on GI level:
if gi1lvl*7+1.5 >= 8 Then
Table1.ColorGradeImage = "ColorGrade_8"
else
Table1.ColorGradeImage = "ColorGrade_" & Int(gi1lvl*7+1.5)
end If
Multiple LUT images (ColorGrade_0 through ColorGrade_8) included, each representing different ambient brightness.
3D & Art¶
Playfield Texture Resolution¶
Recommended max height: 4000px for default low-res version that works on all hardware. Higher-res can be included in image manager unassigned with swap instructions. At 4K, pixels are imperceptible from typical viewing distance.
Flupper renders inserts at 2k, then exports at 256x256 after compositing.
Depth Bias¶
Works like stacking cards: lower/higher values determine render order. For inserts where AO shadow interferes, either adjust depth bias or cut insert holes from shadow layer.
Layers in VPX have nothing to do with rendering order - purely organizational.
PNG Optimization¶
Opening PNGs in Corel Paint Shop Pro and re-saving reduced playfield from 70MB to 25MB. Remove unnecessary alpha channels from non-transparent textures. 8-bit PNG with alpha saves ~75% file size with minimal visible dithering.
WebP Format¶
VPX 10.7+ supports WebP for significant file size reduction. Lossless WebP reduced 40MB playfield to 17MB. Converting entire table reduced from 200MB+ to 124MB. WebP at 90% quality provides excellent results for most textures.
Troubleshooting¶
VPX Texture Memory Error¶
Fatal Error: unable to create texture! D3DERR_INVALIDCALL caused by playfield textures too large for VRAM. Solutions:
- Turn down "max texture size" in VPX settings
- Temporarily export and resize playfield maintaining aspect ratio
- Restart VPX to clear video RAM
VR Black Primitive Bug¶
Material and image swapping on primitives causes them to go black in VR mode. The VR renderer (GL-based) handles texture loading differently. Workarounds: render textures without alpha, use DL/color changes instead of image swaps for VR, or maintain VR-specific primitive versions.
Random Lamp State Corruption¶
Showstopper bug: Lamp states randomly light incorrectly. Root cause: controller.changedlamps not providing correct states. Fix: set UseLamps = 0 in script.
Ball Stuck Detection¶
Quick debug method using VPX editor:
Check x/y/z coordinates to identify stuck ball location.
Resources¶
- PAPA tutorial videos (Bowen Kerins) for shot feel validation
- IPDB manual page 113 for lamp IDs
- Ikuri Arcade (Finland) for hands-on comparison
- Real machine photos overlaid on VPX for alignment
Contributors: iaakki, benji084, sixtoe, wrd1972, cyberpez, flupper1, apophis79, astronasty, bord1947, tomate80, gtxjoe, sheltemke