Skip to content

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:

  1. Start game, open editor (F6)
  2. Type p17.blenddisablelighting=70 and Enter
  3. Adjust value, Enter again to see changes
  4. When satisfied, add value to script in Lampz.Callback line

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:

UpdateMaterial "ToyPlasticON",0,0,0,0,0,0,opacity_value,RGB(255,255,255),0,0,False,True,0,0,0,0

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:

  1. On flash trigger: swap OFF prim images to flash texture
  2. Fade ON prim material opacity from full to zero (reverse: Case 0=full, Case 3=zero)
  3. Simultaneously fade dome DL, playfield overlay flasher opacity, and bloom
  4. 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:

dim bots:bots=getballs:debug.print bots(1).y

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