This tech tip examines the BallPaths specific to the Weird Al module.
The information here was verified against WAMONH 1.5.0.0 with module driver version 1.3.0.0.
The documentation for the module API is excellent. You can find it in %HOMEDRIVE%%HOMEPATH%\.multimorphic\P3\ModuleDrivers\WAMONH\0.9.4.5\UsageInstructions.txt
For the list of BallPaths, see the module definition file in %HOMEDRIVE%%HOMEPATH%\.multimorphic\P3\ModuleDrivers\WAMONH\0.9.4.5\WAMONH.json
For an introduction to BallPaths in general, see the tech tip on Heist BallPaths.
The BallPath API for WAMONH is an improvement over the BallPath API for Heist. See Appendix A for a comparison of the two APIs.
To enable a BallPath on WAMONH, send the event Evt_EstablishBallPath with the BallPath name as the event argument. The current BallPath for the same Entrance will be replaced by the new BallPath. You can see the list of valid BallPath names in the module definition file.
PostModeEventToModes("Evt_EstablishBallPath", "<BallPathName>");
For example:
PostModeEventToModes("Evt_EstablishBallPath", "OuterLeftToOuterRight");
Just be careful not to mistype the BallPath name because the error will be silently ignored.
A static BallPath is when the entrance has only one possible exit. For example, this could be a BallPath for a standup target. Since there is no way to change a static BallPath, it is always enabled. You can establish a static Ballpath if you wish, though this is rather pointless.
Note the BallPath request will be deferred if a custom launch or ball search is in progress. The module driver is smart enough to re-establish the correct BallPaths after the custom launch or ball search ends.
The event sent when a shot is started is:
PostModeEventToModes("Evt_ShotStarted_<EntranceName>", "<EntranceName>");
The event sent when a shot is successfully completed is:
PostModeEventToModes("Evt_ShotMade_<BallPathName>", "<ExitName>");
These events are well documented in the module definition file as p3.BallPaths["<BallPathName>"].StartedEvent and p3.BallPaths["<BallPathName>"].CompletedEvent respectively.
WAMONH has 6 servos: 3 diverters (top, hamster and mezzanine), 2 ramp lifts (right and spiral) and the camera sweep.
The top diverter can be in one of 3 states:
The hamster diverter can be:
The mezzanine diverter can be:
Internally, the mezzanine diverter is known as the CameraLaneDiverter.
The diverter API is not documented. It’s not hard to find out if you use the universal event trace trick from this tech tip. Hint: look for Evt_Servo<ServoName><Position>.
On WAMONH, there is no need to use the internal diverter API. It is much better to control the diverters by establishing the desired BallPaths.
The servo values corresponding to each diverter position are given by GameAttributes configurable in the service menu under Settings/Mechs/Diverters. Within the simulator, they will take their default value of 180 because the simulated module has no local settings. On the physical machine, the diverter GameAttributes will have real values since those are stored physically on the module.
The diverter GameAttributes are:
SettingRightRampLiftDown
SettingRightRampLiftUp
SettingSpiralRampLiftDown
SettingSpiralRampLiftUp
SettingHamsterLaneDiverterClosed
SettingHamsterLaneDiverterOpen
SettingCameraLaneDiverterClosed
SettingCameraLaneDiverterOpen
SettingTopDiverterLeft
SettingTopDiverterDown
SettingTopDiverterRight
SettingCameraSweepLeft
SettingCameraSweepCenter
SettingCameraSweepRight
There is no need to adjust these values unless you have a problem with one of the diverters.
The table below describes all BallPaths in WAMONH.
The BallPath name is implicit in the table to save space. When the EntranceName and ExitName differ, the BallPath name is <EntranceName>To<ExitName>. When the EntranceName is the same as the ExitName, the BallPath name is <EntranceName>, this is indicated by leaving the ExitName blank in the table.
A * in the first column indicates a BallPath that behaves unexpectedly. See the comment below.
EntranceName | ExitName | Comment | |
OuterLeft | OuterRight | Unhindered left to right outer loop | |
Pops | Rear magnet grab and drop below to pop bumpers | ||
RearHole | Rear magnet grab and fling up to rear hole | ||
OuterRight | OuterLeft | Unhindered right to left outer loop | |
Pops | Rear magnet grab and drop below to pop bumpers | ||
RearHole | Rear magnet grab and fling up to rear hole | ||
LeftRamp | RightInlane | Left ramp always leads to right inlane | |
MiniLoopRight | MiniLoopLeft | Loop under camera from right to left | |
MiniLoopLeft | MiniLoopRight | Loop under camera from left to right | |
CrossLeft | OuterLeft | Cross under the left ramp from right to left | |
CrossRight | OuterRight | U-turn under the ramps to right outer loop | |
* | SpiralReject | Up spiral ramp and back down again | |
HamsterLock | Up spiral ramp to hamster wheel. Hamster wheel must be controlled separately. | ||
LeftInlane | Up spiral ramp, to right of mezzanine, to left inlane | ||
MezzLoop | Up spiral ramp, to skywalk, to left side of mezzanine loop. | ||
RearHole | Hole at far top between the pop bumpers | ||
SecretHole | Hole to the left of PopBumperL in outer loop | ||
PopEscape | Hole between PopBumperR and PopBumperB | ||
DropTarget | Drop target dropped. Must be reset separately. | ||
DropHole | Hole behind the drop target | ||
VUK1Entry | VUK1EntryFinished | Hole half-way on left outer loop | |
* | RightRamp | Cannot be established. Appears in other RightRamp BallPahs. | |
* | SpiralReject | Up right ramp, down spiral ramp | |
HamsterLock | Up right ramp to hamster wheel. Hamster wheel must be controlled separately. | ||
* | LeftInlane | Up right ramp, to right of mezzanine, to left inlane | |
* | MezzLoop | Up right ramp, to skywalk, to left side of mezzanine loop. | |
MezzLoop | Mezzanine loop, cannot distinguish direction. | ||
* | MezzRight | MezzRightTarget | Opens access to mezzanine round target. Never completes. |
CameraLock | Mezzanine to camera lock. Camera must be controlled separately. | ||
MezzExit | Drain from mezzanine to left inlane. | ||
CameraTarget | UHF standup target | ||
HamsterTarget | Harvey round standup target | ||
FoodTargetL | Ketchup standup target on mezzanine | ||
FoodTargetR | Mustard standup target on mezzanine | ||
MezzTarget | Red round standup target on mezzanine | ||
LeftRampTarget | V standup target | ||
LeftSideLoopTarget | I standup target | ||
LeftMiniLoopTarget | P standup target | ||
CenterTargetL | Supplies standup target facing PopBumperB | ||
CenterTargetH | Closet standup target facing PopBumperB | ||
PopBumperR | Right pop bumper | ||
PopBumperL | Left pop bumper | ||
PopBumperB | Bottom pop bumper | ||
CameraLockFront | First ball locked | ||
CameraLockMiddle | Second ball locked | ||
CameraLockBack | Third ball locked |
Keep in mind a BallPath that never completes can still be useful to control the diverters.
* CrossRightToSpiralReject starts 4 times for a single shot and never completes.
* RightRamp BallPath cannot be established. If you do, it does nothing leaving the current RightRamp BallPath in place. This BallPath is started and completed as part of the completion of RightRampToSpiralReject, RightRampToLeftInlance and RightRampToMezzLoop but not RightRampToHamsterLock. This BallPath sends an extra started event Evt_ShotStarted_RightRamp with the event argument "Ramp". Notice this is an invalid EntranceName. The completed event is Evt_ShotMade_RightRampToRightRamp.
Just be careful when implementing the Evt_ShotStarted_RightRamp event handler because it will be called twice in quick succession: once as expected with the valid EntranceName "RightRamp" and again with the invalid EntranceName "Ramp".
* RightRampToSpiralReject moves the top diverter to block access to the skywalk from the right ramp. This BallPath is never started nor completed. When making this shot, the started event is Evt_ShotStarted_RightRamp and the completed event is Evt_ShotMade_RightRampToRightRamp. This is surprising because the ball drops down the spiral ramp instead. The completed event is not unique to RightRampToSpiralReject. The application will need to remember which RightRamp BallPath is active if it needs to uniquely identify that shot.
* RightRampToLeftInlane works as expected except there are extra BallPath events between the started event and the completed event:
Evt_ShotStarted_RightRamp with event argument "RightRamp”
Evt_ShotStarted_RightRamp with event argument "Ramp"
Evt_ShortMade_RightRampToRightRamp
Evt_ShotStarted_MezzExit
Evt_ShotMade_MezzExit
Evt_ShotMade_RightRampToLeftInlane
* RightRampToMezzLoop works as expected except it completes twice and there are extra Ballpath events:
Evt_ShotStarted_RightRamp with event argument "RightRamp”
Evt_ShotStarted_RightRamp with event argument "Ramp"
Evt_ShotStarted_RightRamp with event argument "RightRamp”
Evt_ShortMade_RightRampToRightRamp
Evt_ShortMade_RightRampToMezzLoop
Evt_ShortMade_RightRampToMezzLoop // completes a second time
Evt_ShotStarted_MezzLoop
Evt_ShotMade_MezzLoop
Beware the duplicate Evt_ShortMade_RightRampToMezzLoop if you score points in your event handler. An easy solution is to score half the points you truly intend.
* MezzRightToMezzRightTarget moves the mezzanine diverter to give access to the red round standup target from the mezzanine flipper. This BallPath is never started nor completed. Hitting that target starts and completes the MezzTarget BallPath instead.
CrossRampToHamsterLock and RightRampToHamsterLock are the two BallPaths that feed the hamster wheel. Those BallPaths control the diverters but not the wheel itself.
To spin the wheel and keep the ball in, call PostModeEventToModes(Evt_HamsterWheelLock", null);
To spin the wheel and release the ball, call PostModeEventToModes(Evt_HamsterWheelRelease", null);
You can stop spinning the wheel by calling PostModeEventToModes(Evt_HamsterWheelStop", null);
A good time to stop the wheel after a release is when you receive a Grid Event. It’s a good idea to implement a maximum timer in case the release fails.
See UsageInstructions.txt for details.
MezzRightToCameraLock is the only BallPath feeding the camera. The BallPath controls the diverters but not the camera.
To make sure the ball can enter the camera, sweep the camera to the center position:
PostModeEventToModes("Evt_ServoCameraSweepServoCenter", true);
To release locked balls, sweep the camera to the left position and stay there at least 1 second per ball ejected:
PostModeEventToModes("Evt_ServoCameraSweepServoLeft", true);
PostModeEventToModes("Evt_CameraRelease", numBallsToRelease);
where numBallsToRelease is an integer.
See UsageInstructions.txt for details on programming the camera and how to keep track of the number of locked balls. This documentation is truly excellent.
The following table compares the BallPath API for Heist versus WAMONH.
Heist | WAMONH |
Low-level servo API | Not documented, use BallPaths instead. |
PostModeEventToModes("Evt_AddPathByName", new List<string>{ballPathEntrance, ballPathExit}); | PostModeEventToModes("Evt_EstablishBallPath", ballPathName); |
PostModeEventToModes("Evt_AddPathsByName", new List<List<string>> { new List<string> {ballPathEntrance1, ballPathExit1}, …, new List<string> {ballPathEntranceN, ballPathExitN} }); | Send multiple Evt_EstablishBallPath events. |
PostModeEventToModes("Evt_ResetAllPaths", ""); | Send multiple Evt_EstablishBallPath for BallPaths marked as Default. |
PostModeEventToModes("Evt_CachePaths", key); PostModeEventToModes("Evt_ApplyCachedPaths", key); | Not Available but BallPaths are restored after a custom launch or ball search. |
Events sent when a shot is completed: PostModeEventToModes("Evt_<EntranceName>Started", ""); PostModeEventToModes("Evt_<EntranceName>Completed", "<ExitName>"); PostModeEventToModes("Evt_Shot_<EntranceName>To<ExitName>", "<ExitName>"); PostModeEventToModes("Evt_Shot_<EntranceName>", "<ExitName>"); PostModeEventToModes("Evt_ShotHit<EntranceName>", "<EntranceName>To<ExitName>"); | Events sent when a shot is completed: PostModeEventToModes("Evt_ShotStarted_<EntranceName>", "<EntranceName>"); PostModeEventToModes("Evt_ShotMade_<BallPathName>", "<ExitName>"); |
Logs error when adding invalid EntranceName,ExitName BallPath. | Ignores error when establishing an invalid BallPath, can pick an unrelated BallPath. |