Skip to content

Starship Troopers

Extensive table rebuild documentation covering rescaling from 1/2 scale to standard dimensions, nFozzy physics integration, and complex mech implementations.

Build Notes

Table Rescaling - Complete Workflow

Original table built at approximately 1/2 scale (515x1154 VP units). Complete rescaling project documented:

Scale Calculation: - Original: 502 VP units / 50 = 10.04 x 1.0625" = 10.6675" actual width - Target: 20.25 / 10.6675 = 1.89829 (rounded to 1.9, refined to 1.8485 for precision) - Final dimensions: 952x2133 (not standard 952x2162 due to aspect ratio preservation) - Ball: Changed from 27 radius/1.5 mass to standard 50 radius/1.0 mass

Scaling Workflow: 1. Use Select Elements view (Ctrl+Shift+E), sort by object type 2. Select all non-primitives except timers/collections 3. Right-click > Scale, set scale center to 0,0 (critical) 4. Apply scale factor with "Keep Aspect Ratio" UNCHECKED, enter 0 for both X/Y 5. Scale layer by layer rather than all at once 6. Primitives: Multiply X/Y/Z size and position coords by scale factor 7. Ramp heights: Multiply start/end heights AND control point offsets 8. Triggers: Radius-based, scale individually 9. Light falloff: Scale by factor (1.85x for all 151 lights) 10. Kicker hit heights: Scale (e.g., 21 → 50 for ball size change)

Special Cases: - Moving primitives (drop targets, mechs): Scale size + X/Y, leave Z for manual adjustment - Flipper heights needed adjustment after scaling - Physics layer objects must scale precisely to match visual layer - GI flasher alignment requires pixel-perfect precision (used 1.8485 vs 1.85)

Common Pitfalls: - Forgetting objects on "hidden" layers (caused ball traps) - Accidentally scaling collections in "group mode" - Wall heights not scaling (ball falling through ramps) - Depth bias values don't scale (render order, not spatial)

Pro Tips: - Mark scaled layers with asterisk (*) prefix to track progress - Use F6 flymode (alt+arrows, magna buttons to rotate, press 1 to reset before exit) - Press D to open debugger and test values in real-time - Export/import via Blender when primitives need component separation

nFozzy Physics Integration

Phase 1 - Flipper Physics: - Pull latest script from VPW Example Table (more current than docs) - Use era-appropriate presets (90s profile, tweaked to mid-80s for mini flipper) - Flipper strength tuning: Started 3000, ended 3125 for mains, 3225 for mini - Geometry: Length ~147-148 for 3" flippers with rubbers - EndRadius 20.75, BaseRadius 11.5, FlipperRadiusMin 4, Length 114 - Create layer "nfphysics", delete old "newphysics" layer content

Phase 2 - Rubber Dampening: - Add zCol_Rubber_Posts (height 0-50) at all post locations - Add zCol_RubberBand walls between posts - Populate dPosts and dSleeves collections - All rubber physics objects visible during construction to verify Z-height - Common error: z=0 puts object at -25 to 25 instead of 0 to 50

Phase 3 - Other Elements: - Ramps: Apply zCol_Ramp or zCol_MetalRamp material - Slingshots: More complex than expected - Corner posts with dampeners - Rubber animation layer - Plastic blocker wall (top height 50-52, collidable, prevents ball jumping) - Reference: Iron Man VE for clean example - Add slingshot correction code from Example Table

Phase 4 - Tuning: - Playfield friction: 0.15 to 0.25 (ended at 0.15) - Table slope: Difficulty slider 50, use era-appropriate slope (6-7 degrees) - Flipper strength: Tune within era range to match real videos - Pop bumper force: Usually ~10, hit threshold ~5

Lessons Learned: - Don't use post pass ability as flipper strength guide - Remove JP ball speed control code when implementing nFozzy - Kicker forces don't need adjustment for ball mass/size changes - Moving primitives need scale applied to TransZ values

Common Mistakes: - Forgot FlipperTrigger for mini flipper - Initial flipper height on mini still at 25 (half scale) instead of 50 - Banana-shaped mass triggers from old physics left in

Fleep Mechanical Sounds

Collections to Populate: - Rubbers: All zCol posts and rubber bands - Metals: Metal walls and rails (hit threshold = 2) - Targets: Standups and drops (already in TargetBouncer usually) - Rollovers: Physical triggers (star rollovers, lane switches) - Gates: Wire gates and ramps

Migration Process: 1. Copy Fleep code from Example Table (3 videos in #fleep-sounds-guide) 2. Add objects to appropriate collections 3. Remove old PlaySound "fx_something" calls 4. Keep ROM-triggered sounds (solenoid callbacks)

What to DELETE: - All "fx_" prefix sounds (replaced by Fleep) - Old physics sound code - Individual switch sound calls - Speed limiter/ball control code

What to KEEP: - Solenoid sounds triggered by ROM - Mode-specific callouts and music - Unique mechanical sounds not in Fleep library

Edge Cases: - Mini flipper activation sounds needed custom tuning - Spinner sounds needed explicit adding - Slingshot posts weren't in Rubbers collection initially

Critical: Move RollingSound calls to END of subs, not beginning.

Modern Slingshot Construction

Layer 1 - Physics (invisible): - zCol rubber posts at corners with dampeners (in dPosts collection) - Corner posts tangent to rubber animation - Rubber bands (walls) between posts, slightly recessed from sling face - Posts Z=0, ZSize=50 (not Z=-25 to 25!) - Small gap between top corner post and sling wall

Layer 2 - Animation (visible): - Rubber primitive/wall that animates on sling fire - Triggered by switch activation - Animates forward on hit, returns via timer

Layer 3 - Blocker (visible): - Wall at top of sling assembly (bottom height ~50, top height 52) - Represents plastic on top of sling assembly - Collidable to prevent balls from jumping into mechanism

Layer 4 - Switches (invisible): - Visual rectangles representing leaf switches (if desired) - Actual switch triggering via ROM

Script Integration: - Sling corrections code from Example Table - Hit events tied to physics rubber posts - Animation separate from collision detection

References: Iron Man VE (simplest), Batman Forever (polished), VPW Example Table

Scripting

WarriorBug Mech - Stepper Motor Implementation

Complex moving target with 24 collidable wall positions:

Set mBug = New cvpmMyMech
With mBug
    .MType=vpmMechStepSol+vpmMechTwoDirSol+vpmMechStopEnd+vpmMechLinear+vpmMechFast
    .Sol1=17
    .Length=600  'Animation duration in ms
    .Steps=222   'Travel from -110 to +93.5 + 18.5 offset (scaled from 120)
    .AddSw 34,0,1
    .AddSw 33,221,222
    .Callback=GetRef("UpdateWarriorBug")
    .Start
End With

Sub UpdateWarriorBug(NewPos, aSpeed, LastPos)
    For each WarriorBugStuff in WarriorBugGroup
        WarriorBugStuff.TransZ = NewPos-111  'TransZ moves along Y in VPX
    Next
    Position = NewPos * 23 / 222  'Calculate which wall to activate (24 walls 0-23)
    'Drop inactive walls, raise active wall
End Sub

Key Insight: When primitives scale, internal coordinates scale too. For 1.85x scale, TransZ values need adjustment because primitive coordinate space is larger.

Debugging: 1. Set target primitive visible, rest invisible 2. Create overhead POV directly above mech 3. Make collidable walls visible 4. Test with debugger calls 5. Verify target aligns with correct wall at each step

Fast Flips on Sega/Whitestar

Fast flips work by poking values into ROM's RAM to bypass solenoid delays:

  • Williams/Bally (WPC): UseSolenoids = 2 (consistent address)
  • Sega/Whitestar: UseSolenoids = [game-specific] (varies per game)
  • Modern Stern (SAM): UseSolenoids = 1 (use InitSAM instead)
  • Starship Troopers (Sega): UseSolenoids = 15

ROM Version Dependency

RAM address can change between ROM versions. Fast flips on ROM v1.0 may not work on v1.1 for the same game.

Ball Color/Style Options

Const BugBall = 0  '0=Standard silver, 1=Blue bug ball

Sub Table1_Init()
    If BugBall = 1 Then
        Dim b
        For Each b in GetBalls
            b.Color = RGB(10,10,255)
            b.Image = "ball_blue_scratches"
        Next
    End If
End Sub

Better approach: Trigger at trough exit to set ball properties as each ball is created/released.

Flipper Speed Options

Const FlipperMod = 0  '0=Standard black rubbers, 1=Blue modded rubbers

Sub SetFlipperImages()
    If FlipperMod = 1 Then
        FlipperL.Image = "flipperL_on_blue"
        FlipperL.ImageOff = "flipperL_off_blue"
        FlipperR.Image = "flipperR_on_blue"
        ' etc for all 6 flipper images
    End If
End Sub

Created by editing rubber areas in image editor (6 files total: L/R/RS on/off).

Plunger V-Groove for Auto-Plunge

Two narrow invisible ramps form channel down center of plunger lane, keeping ball stable: - Ramps set non-visible - Height set to ball center - Width narrow enough to guide but not trap - Combined with plunger strength reduction (200 → 100 release speed) - Stroke length adjustment

Result: Auto-plunge success rate improved from ~50% to nearly 100%.

Kicker Angle Randomization

' Add randomness to prevent repeatable strategies
sw45.Kick angle + Rnd()*variation, force + Rnd()*variation

Reference Papa Pinball gameplay videos to verify eject variability.

Settings: - Scoop eject: InitKick sw46, 180, 42 - Left kicker: InitKicker sw45, 45, 136, 30, 30

3D & Art

Table Export to Blender

Export from VPX: 1. Turn on all layers 2. File > Export > OBJ Mesh 3. Include entire table

Import to Blender: 1. File > Import > Wavefront (obj) (legacy) 2. Forward: -Z Forward 3. Up: Y Up 4. Scale: 10

Separate Components: 1. Select object (click highlights all connected mesh) 2. Press / (numpad) to isolate 3. Press Tab to enter Edit Mode 4. Enable face/vertex selection 5. Box select part to separate 6. Press P → "Selection" 7. Tab to return to Object Mode

Export back to VPX: 1. Select objects 2. File > Export > Wavefront (obj) (legacy) 3. Forward: -Z Forward, Up: Y Up 4. Apply Modifiers: ON, Selection Only: ON 5. Import in VPX: Insert > Primitive, select .obj 6. Note: Blender export results in scale=100 (vs original 10)

Use Case: Removed floating bolt from hex_bolts primitive attached to Hopper bug for independent repositioning.

Rendering Workflow - Cinema 4D + Octane

Software: - Cinema 4D R20 - Octane Render 4 - HDRI: Kitchen environment (standard), shinyenvironmentblur3 for bakes

Workflow: - All primitives imported with size=10, coords at 0,0,0 (allows easy VPX scaling) - "Hi-rez screenshot projection" for quick ramp plastic refractions

Ramp Plastic Baking: 1. Export table from VPX, import to C4D 2. Swap all materials to camera-projected material 3. Take hi-rez overhead screenshot from VPX 4. Project screenshot from overhead parallel camera onto geometry 5. Won't align perfectly but close enough for refractive plastics 6. Adds ramp reflections without placing every insert manually

Dynamic Ball Shadows

Added in apophis testing-48 update: - Ball image updated - Ball scratches texture updated - Environmental image updated - Emission scale adjusted - Flipper dynamic lighting tied to GI state

Note

Dynamic shadows don't work well on dark tables (Metallica left them off).

Troubleshooting

GI Flasher Image Alignment - World vs Wrap Mode

Symptom: Playfield image shifted 1-3 pixels when GI toggled.

Root Cause: Playfield mesh size didn't exactly match table dimensions (952x2133 table vs 952.75x2134.9 mesh from imprecise scaling).

Investigation: 1. Exported all 4 playfield images from Image Manager 2. Imported into Pixlr as layers 3. Toggled layers - found pfgi.png shifted 3px right

Solution: 1. Rescaled playfield mesh with precision factor 1.8485 (vs 1.85) 2. Set GIFL1 flasher corners to exact mesh corners 3. Adjusted table height by 0.17 VP units 4. Used "World" mode for GIFL1

Flasher Mode Explanation: - World mode: Image sized to full table, flasher shows window into image - Wrap mode: Image stretched to fit flasher area - World mode required for GI because mesh must match table size exactly

Pro Tip: Use corner point positions to measure actual primitive dimensions.

Ball Stuck Diagnostics

With table loaded and ball stuck, press D for debugger, click "Editor":

dim b:b=getballs:debug.print b(0).x & " " & b(0).y & " " & b(0).z

Change b(0) to b(1), b(2) etc. if multiball. Returns exact X, Y, Z coordinates.

Common Causes: - Ramp heights too low (ball rolls under) - Invisible physics walls misaligned after scaling - Gaps between primitives - Wall top height too low for new ball size

Lighting Falloff Scaling

After rescaling, hard-edged light boxes appeared on playfield.

Cause: Falloff defines fade distance in VP units. When table scaled, lights moved but falloff stayed same absolute value.

Solution:

Dim light
For Each light in Lights
    light.Falloff = light.Falloff * 1.85
Next

Use rounded integer values to avoid European decimal separator issues.

Scope: 151 lights across all layers (Lights_BlurU, General_Illumination, FlasherCaps, Lights, Lights_Blur, flasherside).

Cabinet Flasher Height Scaling

Cabinet-side flashers need script value adjustment:

Original (1/2 scale):

If Table1.ShowDT = False then  'Cabinet/VR
    f125.rotx = -22: f125.height = 230
Else  'Desktop
    f125.rotx = -7.45: f125.height = 160
End If

Scaled (1.85x):

If Table1.ShowDT = False then
    f125.rotx = -22: f125.height = 425  ' 230 * 1.85
Else
    f125.rotx = -7.45: f125.height = 296  ' 160 * 1.85
End If

Rotation values (rotx) are angular, not spatial - do NOT scale.

VPX Editor Quirks

Collections Manager: - Can't read full object names (no resize/hover tooltip) - Workaround: Delete and recreate with better names - Collections that fire events MUST save and restart to work - Right-click context menu sometimes unselects all (try again)

Zoom Bugs: - Zooming in fully prevents zooming out - Workaround: Click backbox button twice to reset view - OR use zoom tool from left menu (not Ctrl+mouse)

Flymode (F6): - Alt + arrows = move camera - Magna buttons (Z/?) = rotate view - Press 1 before exiting to reset POV - Mac: remap magnas if only one Ctrl key

Scaling: - Selecting group can change unintended objects - Turn off "Group" mode unless needed - "Fire Events" must be ON for collidable collections

Debugger: - Call methods in real-time: object.TransY = value - SetLamp 200, true/false to toggle GI - Orbital VPX wiki has all properties/methods - Works best in 10.7.3 64-bit

Target Hit Threshold Tuning

Green and red standups inconsistently registering at default threshold (1.0). Fixed by setting to 0.5.

Related Fix - Target Animation:

' OLD (broken):
Sub Target_Hit(): Target.rotx = Target.rotx + 4: End Sub

' NEW (fixed):
Sub Target_Hit(): Target.rotx = -4: TargetTimer.Enabled = True: End Sub
Sub TargetTimer_Timer(): Target.rotx = 0: TargetTimer.Enabled = False: End Sub

Absolute positioning prevents targets rotating upside down when hit rapidly.

VPX 10.7 Beta Stability

Initial Concerns (early 2021): - Crashes during table building - Broke 10.6 compatibility completely - SSF had issues - Some preferred staying on 10.6

Benefits: - Layers feature (major workflow improvement) - Free window arrangement - Various editor UX improvements - Performance optimizations

Recommendation (2023): Use 10.7.3 64-bit specifically - debugger works correctly, most stable.

Game Knowledge

Starship Troopers Gameplay

Key Shots: - WarriorBug mech: Moves back progressively, eventually exposes scoop for big points - Brain Bug: Raises/lowers on solenoid (rocket motion, not smooth) - Left scoop: Skill shot, repeatable but risky - Right ramp: Can fail back to bumpers via fallback hole

Scoring Strategy: - Left scoop loop exploitable (5M, 10M, EB, 15M, 20M increasing) - Player scored 280M ball 1 by repeating

Skill Shots: - Plunge with hold left flipper = disable magnets, different lane feed

Multiball: - Brain Bug multiball cage holds multiple balls - Balls released from plunger may feed directly to WarriorBug scoop

Difficulty: - Outlanes not major threat - Wide flipper gap is real danger - Ball save has no grace period (ROM behavior)

Table Design Details

Statistics: - Designer: Joe Balcer, Joe Kaminkow - Manufacturer: Sega Pinball, 1997 - Theme: Movie tie-in

Unique Features: - Large warrior bug multiball cage (moving mech) - Brain bug on solenoid popper - Hopper bug on lower left playfield - Complex ramp system (noted as "nightmare to remove") - Wire ramps and plastic ramps

Build Quality: - Backboard is thin plyboard false front (unusual) - Left flasher sits partially inside backboard via cutout - Dropship wings extend behind playfield wall

Decals: - Censorship stickers (decals 11, 12, 13) optional for regions requiring blood/gore censorship - #13: Between flippers - #11, 12: Ramp inlanes

Ball Save: Quite long on real table. Short plunge to outlane should still be within window.

Assessment: Considered one of Sega's best tables. Loaded with features, unique for Whitestar/Sega era.

Resources

Sega Pinball Reference Materials

Primary Sources: - Sega service manuals more accurate than Williams for component placement - Blueprint practically perfect for layout - Toys are commercially available Galoob action figures (not custom)

Image Resource Pack: SST Reference Pictures.zip - Brain Bug assembly photos from parts sales listings - Warrior Bug multiball cage details - Flasher placement in cage (image-16.jpg shows exact locations) - Backboard construction details

Specific Findings: - Left red flasher sits partially inside backboard - Banana-shaped flasher mount goes through backboard - Dropship left wings extend behind playfield wall - Brain bug cage uses solenoid popper (rockets up/down)

Search Terms: - "Galoob Starship Troopers" for toy references - Warrior Bug toy model #880-5005-00 from Marco Specialties - Parts listings often include detailed assembly photos

VPX Object Export for Blender - Settings Reference

Export from VPX: - File > Export > OBJ Mesh - Turn on all layers before export - Export entire table (not individual objects)

Import to Blender: - File > Import > Wavefront (obj) (legacy) - Forward: -Z Forward - Up: Y Up - Scale: 10

Export from Blender: - File > Export > Wavefront (obj) (legacy) - Forward: -Z Forward - Up: Y Up - Apply Modifiers: ON - Selection Only: ON (if partial)

Import to VPX: - Insert > Primitive, select .obj - Note: Blender export results in scale=100 (vs original 10) - Both valid, just different conventions

Why These Settings: VPX and Blender use different coordinate systems and units. These settings ensure proper orientation and scale.

Best Practices

Managing Complex Rescaling Projects

Versioning: - Incremental naming: filename_scaled-01.vpx, _scaled-02.vpx, etc. - Change log at top of each file - Share via Dropbox for async collaboration - Upload frequently for review

Layer Naming: - Prefix scaled layers with asterisk: *vpx_stuff, *Korpus - Track completion progress - Remove prefix before release

Collaboration: - "Call dibs" before making changes - Upload WIP files frequently - Use Discord for rapid Q&A and screen sharing - Specific questions with screenshots better than general "how do I..."

Learning Approach: - Start with complicated project as "baptism by fire" - Read Example Table and recent VPW releases as reference - F6 flymode essential for 3D spatial debugging - Don't be afraid to ask "dumb" questions

Common Mistakes: - Making changes across many files before testing - Assuming objects on hidden layers don't matter - Not documenting decisions - Trying to remember manual adjustments

Morale: - "One more time" became running joke (rescaled 3+ times) - Celebrate small wins - When stuck, ask for help - Recognize knowledge extraction time - skills transfer to future projects

Sound Volume Balancing

Mechanical sounds often too loud in initial Fleep integration:

Const BumperSoundFactor = 3      ' Was 6
Const VolumeDial = 0.5           ' Was 1.0

Tuning Process: 1. Play with headphones 2. Identify which sounds overpower others 3. Adjust per-mechanism factors first 4. Use VolumeDial as global trim 5. Test in cabinet with shakers

Bumpers: Often loudest offender, can mask other sounds and become fatiguing.

Inlane Slowdown Code

Real tables have friction and slight upward angle at inlane entry:

Sub InlaneLeftTrigger_Hit()
    ActiveBall.VelX = ActiveBall.VelX * 0.8
    ActiveBall.VelY = ActiveBall.VelY * 0.8
End Sub

Reduction factor (0.8) adjustable to match real table feel. Watch reference videos.

Release Checklist - Final QA

RC1 → RC2: - Reworked ramp rolling sounds - Sound effect file cleanup (remove unused fx_ files) - Lock all objects - VR backglass update - Cabinet screenshots

RC2 → RC3: - VR flipper buttons animated - Cabinet brightness corrections - User-submitted texture improvements

RC3 → RC4: - Minor collision geometry adjustments - Physics material corrections - Volume balance - Top comment block cleanup

RC4 → RC5: - Inlane slowdown code - Kicker randomization - Default background image - Final balance pass

Release 2.0: - AO default OFF - Normal map cleanup - All objects locked - Version history at top of script - Credits in script header

Common Last-Minute Fixes: - Volume balance - Default render settings (AO, ball reflections) - Desktop background image - Object locking

Digital Nudge Strength

Digital nudge and tilt sensitivity must be balanced:

Symptoms: - Too strong: Can save anything from outlanes - Tilt too insensitive: Can nudge with impunity

Testing: 1. Deliberately put ball in dangerous positions 2. Try to save with nudge 3. Adjust if too easy or impossible 4. Test tilt sensitivity - should trigger with excessive nudging

Compare to other VPW tables and real machine.


Contributors: Eighties8, iaakki, apophis79, Sixtoe, DJRobX, nFozzy (manners7344), Deleted User (Knorr), MrH, tomate80, Uncle Paulie, Aubrel (houb.)