Jump to content



Photo
- - - - -

Visual PinMAME Scripting 104


  • Please log in to reply
7 replies to this topic

#1 destruk

destruk

    VPF Veteran

  • VPF Staff
  • 6,307 posts
  • Location:Colorado Springs, CO

  • Flag: United States of America

  • Favorite Pinball: Ultrapin!



Posted 30 March 2010 - 08:09 AM

This is in three sections as this topic is quite complex. - Please hold your posts/comments until all three sections are posted in this thread, and you can read them at your leisure.

Visual PinMAME Scripting 104 - Mechanics Handlers (TOYS! Part 1 of 3)
--------------------------------------------------------------

Most later model games have custom playfield objects which are motorized or unique for that specific game.
These are playfield toys. Like everything else, they can range from simplistic to ludicrously complex.
A lot of thought goes into these devices. You have a few different classifications available.
Is it for show only - such as the pole dancers in Sopranos?
Must it be synchronized to audio like the talking fish?
How much of the object is designed to move - the eyes, mouth, and eyebrows of rudy?
Does it eat the ball, interact with some ball lock or subway system, entirely rotate like the Judge Dredd Dead World?
Does it pick up the ball and allow full player control like the Johnny Mneumonic glove?

Generally, the more complex the toy is, the more attractive a machine can be to draw in a casual player.
However, the more complex the toy is, the higher the chance will be of a mechanical problem, and it could be quite difficult to repair.
As usual, this tutorial will not cover every available toy that has ever been created. The purpose of this tutorial is simply
to ease the frustration resulting from attempts to get a toy working for a pinball simulation using Visual PinMAME and Visual
Pinball. You will quickly discover that making a toy in VP, without a romset, is a whole lot easier than having to satisfy a romset and
prewritten game logic.

The absolute first thing to do when recreating a table that has a playfield toy, is to see if it has been correctly emulated before.
If it has been done correctly before you can save a lot of time by using the proven method. There is no reason to reinvent the wheel
and possibly screw it up in the process. Most playfield toys can ONLY WORK ONE WAY when there is a romset involved. As for the
visual presentation and animation, feel free to handle that however you like, but as far as scripting and methods go, if you make
changes to how it operates, it could fail during a game, under specific conditions, or entirely provide inaccurate results.
A broken toy could be a game breaking problem, and will cost you, or someone else, a lot of time trying to fix it.

With Visual Pinball, you have THREE ( 3 ) options to choose from when deciding to implement simulation of a playfield toy device.
Choice 1 - Use a built-in, precoded mechanics handler that is already available in the Visual PinMAME DLL file
Choice 2 - Create a custom mechanics handler in the script yourself
Choice 3 - Use standard visual basic code with timers or other methods to get the toy 'working'

If you go with Choice 2 - the custom mechanics handler, then whenever you make changes to the scripted toy it is a good idea to
delete the nvram file before testing your new changes. This way the old settings will not interfere with the current ones in use.
I'll go over that a little bit better later in this tutorial.

OK, so to start I'll cover choice 1 - prebuilt 'internal' mechanics handlers. They are internal because to change them you would
need to recompile Visual PinMAME. And in order for your table to work the same on everyone's computer, you would need to ensure
that they have the same DLL you used. Usually this is not a problem as most of the internal mechanics handlers are correct already.
If one is in fact, not correct, you can either fix it in the source code and submit it to the SVN repository to correct it for
everyone in a newer release of Visual PinMAME, or you can not use it and make adjustments to your custom scripted mech handler, or use
choice 3 - standard visual basic code with timers or other methods.

Before there was Visual PinMAME, back when there was simply WPCMAME to emulate games with, the original PinMAME dev team created what
they called "Simulators" for PinMAME. This allowed anyone to insert coins, toggle switch contacts, and see playfield 'lights' and
DMD animations, and hear the sounds of a game by pressing key combinations on the keyboard. In effect, simulators allow you to
'play' a game without using a visual pinball table or external software. The simulators are still included in every version of
PinMAME as well as Visual PinMAME. For Visual PinMAME, load a table and change the "ShowDMDOnly=" line to FALSE and then run the
table. Games that have internal simulators will have some keys listed. To use a simulator with Visual PinMAME, change the
"HandleKeyboard=" line to TRUE. This way any keys you press will be picked up by the Visual PinMAME window.

It is most common to have simulators available for WPC games - as they were the first games to be emulated in PinMAME. There are also
a few simulators done for other game platforms - such as the mini flipper for Stern's Monopoly. You can see which games have simulators
by looking at the source code for Visual PinMAME here:
http://pinmame.svn.s...k/src/wpc/sims/

For our current purposes, click on the link for "wpc". You will see two folders - one is called "full" and one is called "prelim".
For the most part, "full" is nearly entirely playable in the simulator. "Prelim" only has a few options. Click on "full".
Now click on "ij.c" - this is the wpc driver and simulator for Williams' Indiana Jones. Next click on Revision 1824's VIEW link.
This will give you the file on the screen with line numbers.

Most internal mechanics handlers are located at the end of the file - so scroll down to line number 720 and you'll see "handlemech".
This is the section we are concerned with.
if ((mech & 0x01) && core_getSol(sCenterDropUp))
This means the internal mech handler #1 is the center drop target bank
Mech #2 is the Totem Drop Target which goes up and down
Mech #4 is the tilting Path of Adventure
Mech #8 is the rotating Idol toy

To use these internal mechanics handlers in your script, you need to add this code to table_init:
CODE
Controller.HandleMechanics=15


Why 15? Because 1+2+4+8=15 smile.gif
If you just wanted to use the internal handlers for the Path of Adventure and the Idol then it would be 12.

Now, this is where it becomes a little confusing, so please try to pay attention. What the internal mechanics handlers do is they
handle the switches, monitor solenoids, and provide some kind of feedback to the table script or display to make the game think the
toy is real, and that it is operating correctly. By closing/opening switch contacts at the appropriate times, the game is fooled
into thinking everything is working as designed. There isn't a way to 'push' data to visual pinball through Visual PinMAME, so to
use the internal mechanics handlers, you must have something to query the status for you at regular intervals. This can be done
with an enabled timer object, or one of the standard callback routines: MotorCallback, LampCallback, or GICallback.
GICallback is only called when the General Illumination level changes on the table - which shouldn't be used for this as the toy will
usually change state without the GI changing. LampCallback is updated 60 times per second ( 60hz ) and is only called when a lamp state
changes. MotorCallback is called every time a solenoid and/or lamp changes, so MotorCallback is both reliable and efficient.

Usually, for playfield toys, I prefer using MotorCallback, or using standard VP timer objects.
In the script to add MotorCallback, you would add this line.

Set MotorCallback=GetRef("UpdateToys")

While you can use both methods, a callback and a timer, using both will not have a significant improvement in the speed of execution.
Pick one or the other for ease of debugging.

For a timer, you want it to be set to 1ms and enabled so it is called as fast as possible.
For even faster updates, you can add an enabled timer object to the table called vpmFastTimer with an interval of 1. This will have an
extreme impact on custom scripted mech handlers.

In our MotorCallback example, you will be using similar code to the following:

CODE
Dim OldPOAPos,CurPOAPos
Dim OldIdolPos,CurIdolPos
OldPOAPos=0
OldIdolPos=0

Sub UpdateToys
    CurPOAPos=Controller.GetMech(2)
    CurIdolPos=Controller.GetMech(3)
    If CurIdolPos<>OldIdolPos Then UpdateIdol
    If CurPOAPos<>OldPOAPos Then UpdatePOA
End Sub


If you look at the source code again for the IJ Mech Handler - lines 762+, you see you only get script access to mechanic numbers
2 and 3. The first mechanic handler 0x01 for the ENT targets is Controller.GetMech(0), the second one for the Totem drop target 0x02 is
Controller.GetMech(1). The Path of adventure 0x04 is Controller.GetMech(2), and the Idol Position 0x08 is Controller.GetMech(3).

For the GetMech command, it checks if it is being asked for #2. If yes, it returns the POA position, if no, it returns the idol position.
In our script example above, it queries the current data for the POA and the Idol, compares them to the last result, and if they are
different, it updates the screen display with UpdateIdol or UpdatePOA, as needed. At the end of those routines they will copy the
current status to the old variable with something like OldIdolPos=CurIdolPos or OldPOAPos=CurPOAPos. If both values are different for
CurPOAPos and CurIdolPos, both update routines will be executed - UpdateIdol followed by UpdatePOA.

Naturally, UpdateIdol's subroutine would have Visual Pinball update walls, change an emreel, move balls from kicker to kicker, etc,
and UpdatePOA would change the image and/or ball physics values to handle the Path of Adventure.

Since we are only truly using the mech handler for the idol and POA in this section, go back and change the handlemechanics value from
15 to 12. 12 would be 0x04 + 0x08 for mechanics 3 and 4.


Let's do one more internal mech handler example and then I'll go on to Choice 2 (custom scripted mechanics handlers).
Open corv.c
It is in the WPC/Prelim folder
For revision 2518 click on view and scroll down to the end.
Line 398 has a drawmech line which tells us we have 3 handlers here - one for the blue car, one for the red car, and one for the engine.
The blue car is mech 0x01, red car is 0x02, and engine is 0x04
Line 474 is the getmech routine which has all three script accessible - 0x01 is GetMech(0), 0x02 is GetMech(1), and 0x04 is GetMech(2)
So to get the current Blue Car position you would use Controller.GetMech(0) in your query routine.

For the HandleMech line in the script, to use all three it would be Controller.HandleMechanics=7 ' 1+2+4

CODE
Set MotorCallback=GetRef("UpdateToys")

Dim OldBlue,CurBlue
Dim OldRed,CurRed
Dim OldEng,CurEng
OldBluePos=0
OldRedPos=0
OldEng=0

Sub UpdateToys
    CurBlue=Controller.GetMech(0)
    CurRed=Controller.GetMech(1)
    CurEng=Controller.GetMech(2)
    If CurBlue<>OldBlue Then UpdateBlue
    If CurRed<>OldRed Then UpdateRed
    If CurEng<>OldEng Then UpdateEng
End Sub


Again, the update routines "UpdateBlue" and "UpdateRed" and "UpdateEng" would change the graphics on the screen, and update the values of
OldBlue, OldRed, and OldEng with OldBlue=CurBlue, OldRed=CurRed, and OldEng=CurEng. The internal simulator itself handles all the
related solenoids and switches involved for the playfield toy being simulated for you all by itself.

If you need to, you can still use the SolCallbacks the simulator uses to add other changes to the presentation with Visual Pinball.
An example would be SolCallback(17)="TextBox1.Text="
Solenoid 17 in Corvette is the Race Direction solenoid. If you wanted to see if that was enabled, that line will toss the word
"TRUE" or "FALSE" into a textbox called Textbox1 in your table. You are still limited to one MotorCallback in your script -
meaning, whatever one was defined last overrides all the others. Try to be neat and don't duplicate lines of script.
You are also limited to one SolCallback line per solenoid number. So having two SolCallback(17)'s will only utilize the last one
declared.

If possible, try to keep all, or most of your code together for playfield toys - it makes debugging a lot easier if it's all in one
place. ie - the code above is good, and go ahead and stick the Sub updateBlue, in its entirety, directly below the updatetoys
subroutine, followed by the routine for UpdateRed and UpdateEng.

If you want to create more internal simulators for Visual PinMAME, it is open source, so feel free to do so. As far as I know - we
have never turned down an additional simulator for inclusion. wink.gif

In the rare cases that an existing internal simulator isn't accurate, or in the more common cases, that a simulator isn't available
internally for your current project, you can make your own through the script itself. If it is done in your script you have direct
access to change it at any time, you can save and restore values yourself if desired through the script, and the internal simulators
will not have any influence on how your game works in the future. ie if an internal simulator is changed or updated, your game will
still work exactly as it did before even with newer versions of Visual PinMAME. This brings me to choice 2 - custom mechanics handlers.

Build a fire, vipers love the heat.


#2 destruk

destruk

    VPF Veteran

  • VPF Staff
  • 6,307 posts
  • Location:Colorado Springs, CO

  • Flag: United States of America

  • Favorite Pinball: Ultrapin!



Posted 30 March 2010 - 08:19 AM

Visual PinMAME Scripting 104 - Mechanics Handlers (TOYS! Part 2 of 3)
--------------------------------------------------------------

Custom Scripted Mechanics Handlers
As Visual PinMAME's popularity grew, thanks to Visual Pinball's exploding user base, internal PinMAME simulators became less
popular to work on. Why settle for a black display and a few lights and individual key presses when you can have a full color
3D representation of the same game, with an animated ball and animated flippers? My point exactly. The supported game list
expanded - new generations and manufacturers have been added, and now we have access to about 1000 games as compared to the
original 40 or so WPC titles. Thanks to table authors like yourself (you are reading this so I think you might be making games),
there are hundreds and hundreds of Visual PinMAME scripted tables recreating a large selection of solid state machines.

Due to necessity, and lack of internal simulators keeping pace with publicly worked on released tables, WPCMame decided to allow
scripting of new mechanics handlers by the end user or table author. It is because of this feature, that we have so many complete,
working tables to play today. Any game that does not have an internal mechanics handler MUST either rely on a custom created handler,
or choice 3 - brute forcing it in VP with timers and other means, to get a working toy under rom control. The only other option
is a broken or missing playfield toy, which is just plain unacceptable to most people.

Any internal machanics handler can be implemented with a custom mechanics handler script, and any custom mechanics handler you
create could be implemented as an internal handler. The main reasons a toy wouldn't work with Visual PinMAME are:
#1 - There could be a bug in the emulator itself for Visual PinMAME
#2 - Improper implementation of switches and solenoids, and lack of information on how the toy really works

I have run across real pinball machine owners who couldn't explain how something operated or what switches were involved. That sort
of thing doesn't surprise me much anymore. ie - they insert coins and play a game but have no clue how many physical balls are in it.

To create a custom mechanics handler through the script, you want to try to figure out as much as possible so you can get it correct.
This could involve tracking down real owners, looking at the real machine in person if possible, looking at video of the machine,
running the actual toy test diagnostics on the real machine, checking youtube for footage, looking at photos of the game, reading the
game manual, looking at parts diagrams, playing the game a few times, looking at the Visual PinMAME source code, looking at previous
versions of the same table in Visual Pinball, looking at the table file if it exists for Future Pinball, experimenting and making notes
on what the game seems to be doing in Visual PinMAME and/or PinMAME32...in other words, you want to learn exactly what it does, as best
as you can.

To solve the problem, it helps to have a thorough understanding of the issue, but you don't need to know everything... smile.gif
Anyway, it can be easy, and it can be real hard, depending on the toy and available data. If after doing the above, you still need help,
ask on vpforums.org. You could also try to call the manufacturer of the real machine. I have talked to Chas at Stern Pinball and another
Stern employee on their customer service line and they are generally helpful. You could also contact the game designer as a last resort.
I really don't like thinking about contacting Steve Ritchie to ask him about one of his game's toys - mainly because he is one of my
'heroes' so I don't want to bug him about such trivial items - his time is important. It still remains an option though - can't hurt to
ask if all else fails.

Be sure to check out vbsdoc.html to follow along. I will go through this once, and then show some examples.
To create a custom mechanics handler, you need to give it a name, so for this we will use "TOY" smile.gif

Dim TOY

Set Toy=New cvpmMech

I usually dim the name as a global variable, and set up the options in table_init so it is all handled and started immediately after the table
renders. This sets TOY to a custom scripted mechanic.

To define a custom mech handler you must define the type of toy you are recreating.
The type definition for the toy is made up of 4 pieces.

The first piece has four possible options. These options are the ONLY ones supported by the custom mechanic handler.
I know for a fact that some toys will not be able to be emulated by the options available, which means those can only work by
using choice 3 - brute forcing through VP by any means necessary... smile.gif I'll cover a few of those in Part 3 of this tutorial.
For the most part though, these are sufficient.

vpmMechOneSol, vpmMechOneDirSol, vpmMechTwoDirSol, and vpmMechStepSol
OneSol means it goes in one direction and one solenoid turns it on or off. - example would be the Sopranos Pole Dancers
OneDirSol means the first solenoid is on/off, second solenoid is the direction - example would be the Terminator 2 Gun
TwoDirSol means the first solenoid controls clockwise movement and second solenoid controls counter-clockwise movement
An example for TwoDirSol would be the soccer ball spin disc in World Cup Soccer '94
And vpmMechStepSol is used for stepper motors controlled by two solenoids. Examples of this would be the drag strip cars in Corvette

The second piece defines how it moves. It can move in a circle or loop around to the beginning on its own, it can reverse, or it can
stop when it reaches the end of the range of motion. Those are vpmMechCircle, vpmMechReverse, and vpmMechStopEnd respectively.

The third piece is the speed of the mechanic - if it travels at the same speed all the time it is Linear, if not it is NonLinear.
vpmMechLinear and vpmMechNonLinear.

The last piece is optional - you don't need to use it. If not specified, it defaults to vpmMechSlow and vpmMechStepSw.
vpmMechSlow is updated 60 times per second, and vpmMechStepSw is basing the movement on number of incrementations from the home
position to the end of range of motion. vpmMechFast is updated 4 times faster than vpmMechSlow - 240 times/second.
Finally, vpmMechLengthSw is updated based on the "length" value of the mechanic.

So, for our type of toy, we use a mix of options for those four pieces to define it.
Toy.MType=vpmMechOneSol + vpmMechCircle + vpmMechLinear
That would be sufficient for the Sopranos Pole Dancers... smile.gif

Next, you must tell it what solenoids are controlling the toy.
Toy.Sol1=18 'dancer solenoid number

And then we need to tell it how much time must elapse for the toy to move. We do this with the Length property.
Toy.Length=40

The length is actually the amount of time, in milliseconds, that the specified solenoids must be enabled for, to move a single step
in the progression from the start to end position.

Next we specify how many 'steps' the toy has from the start to the end position.
Toy.Steps=14 'using 14 frames of animation

Every time a new 'step' is reached, the toy definition will call the update routine specified by the callback below.

For ease of learning, I'll set up the Callback routine next.
Toy.Callback=GetRef("UpdateDancers")

Now in the case of the pole dancers in sopranos, no switches are involved - they simply spin around. So I leave that out.
However, so I don't need to go over this later, if a switch was involved you have three options: AddSw, AddPulseSw, AddPulseSwNew
AddSw specifies a single switch to be updated by the mechanics handler. The syntax is .AddSw Switch Number, First Position, Last Position
Toy.AddSw 12,0,0 'this would mean that every time the toy is at position 0, the custom handler would close switch 12. When the toy leaves
position 0 the handler would open/clear switch 12.
Toy.AddSw 12,5,8 ' This would mean that when the toy is at position 5 it closes switch 12, and if it reaches position 4 or position 9
it will open/clear switch 12.

AddPulseSw specifies a switch to be pulsed while the toy is moving. Syntax is .AddPulseSw Switch Number, Length between pulses in steps,
length of each pulse in steps.

Toy.AddPulseSw 12,2,1 ' This would mean that every 2 positions, switch 12 will be pulsed for 1 position.

AddPulseSwNew - this feature was added specifically for the Corvette Car drag strip, at my request. However, it could also be used
for the Johnny Mneumonic Data Glove toy. Basically it is used for position encoders on stepper motors. This will pulse switches
as fast as possible for a toy. Luckily, only 2 or 3 toys in existence would depend on this functionality.
The syntax for this one is .AddPulseSwNew Switch Number, Interval, Start, End.
Toy.AddPulseSwNew 12,2,1,100 ' This would mean that the mechanic handler will pulse switch 12 every other step (interval of 2 steps),
beginning at step 1 and ending at step 100.

AddPulseSwNew was a required addition as I had gone over the limit of AddSw, and AddPulseSw just simply wasn't fast enough for what the
game was expecting. To make AddPulseSwNew even faster, you can add vpmMechFast to the type, as well as adding an enabled timer object to
the table called "vpmFastTimer" with an interval of 1.

Another two optional properties to add are Acceleration and Retardation. These are .Acc and .Ret. These are most useful to be used
with spin discs, as well as swinging pendulum type toys. Acceleration is the amount of time required to reach full speed.
Retardation is simply a multiplier for how much time it takes to come to a stop after the solenoid turns off.
Toy.Acc=50
Toy.Ret=.2

The above code means it takes 50ms to get to full speed, and it comes to a stop 10ms after the solenoid turns off.
If the code is missing it is assumed that the mechanic reaches full speed instantly and stops instantly.

Finally, now that all the options have been defined and set up for the toy, you can start its operation.
Toy.Start

At this point the toy is running, monitoring the solenoids, changing the specified switches, and tracking everything required for you.
When the position changes it will execute the specified callback routine.
The callback routine will be provided with 3 variables, so your callback routine must follow a format to accomodate the supplied data.

Sub UpdateDancers(aNewPos,aSpeed,aLastPos)

The first supplied number is the new position/step value of the toy, followed by the speed of the toy, and then the previous position
of the toy. The data supplied is very useful for your presentation, especially if you have defined arrays. Define your array
outside of the update routine so it isn't executed unnecessarily.

Dim DancerWalls
DancerWalls=Array(Dancer0,Dancer1,Dancer2,Dancer3,Dancer4,Dancer5,Dancer6,_
Dancer7,Dancer8,Dancer9,Dancer10,Dancer11,Dancer12,Dancer13)

The underscore used as above simply tells the script editor that the line of code continues on the next line.

Another option would be to simply create a collection. Provided you add the walls to the collection in the desired order that would be fine.
In our Sopranos example, we have 14 steps - which is 14 positions, but arrays, collections, and actual step references begin at 0 - so
if you are using AddSw, possible step values are 0 through 13. Keep that in mind while defining your toy.

Now, back to updateDancers... smile.gif
Sub UpdateDancers(aNewPos,aSpeed,aLastPos)
DancerWalls(aLastPos).IsDropped=1
DancerWalls(aNewPos).IsDropped=0
End Sub

The aSpeed variable for this example we're simply going to ignore. The drop and raising of walls is efficient, and all that is
needed in this instance.
There are cases where the values for aOldPos and/or aNewPos will be out of range. ie it could return a -1 value or a 14 value.
If this happens, you can add a validity check to the code like this:

Sub UpdateDancers(aNewPos,aSpeed,aLastPos)
If aLastPos>-1 and aLastPos<14 Then DancerWalls(aLastPos).IsDropped=1
If aNewPos>-1 and aNewPos<14 Then DancerWalls(aNewPos).IsDropped=0
End Sub

When setting up your animations, give it some thought to your presentation method. In this case, the dancers always move at the same
time, at the same speed, in different directions. However every time the left dancer's position changes, the right dancer's position
changes, with the same amount of rotation. Therefore, you 'could' put the image of both dancers on the same wall each frame.
ie when the left dancer is facing 90 degrees, the right dancer always faces 270 degrees, so both dancers could be in the same graphic.
The fewer walls that have to be dropped and raised at each update, the smoother the table will run.
I realize this is a very minor thing to be worried about, however, in specific instances it can make a big difference.

You can query the toy's current position and speed from anywhere in the script after the toy has been defined and started.
Toy.Position returns the current step.
Toy.Speed returns the current speed of the toy with 0 being stopped.

You can also update switches in the update routine itself, if necessary - however, be careful. You probably don't want to
modify switches that are already used in the .AddSw definition of your toys or it could generate a conflict in their states.

If you need your mechanic to run faster than it is, using vpmMechFast in conjunction with a vpmFastTimer in the table will run it as
fast as programically possible. If you are using the .Length property to modify switch status then you will need to also go back
and change the durations to account for the faster operation. It can take some trial and error to get a toy correct.
With a custom mechanic handler, the position and state of the toy will be saved in the nvram file for the romset every time the
table is 'played'. If you change the length of the steps, or the number of steps, or the mechanic type, it could generate errors
when you replay the table with your new changes. To clear out saved settings, either delete the specific nvram file so it creates a
new one, or default the romset through the diagnostic menus.

Part 3 will start with some full custom scripted toy examples and definitions.

Build a fire, vipers love the heat.


#3 destruk

destruk

    VPF Veteran

  • VPF Staff
  • 6,307 posts
  • Location:Colorado Springs, CO

  • Flag: United States of America

  • Favorite Pinball: Ultrapin!



Posted 30 March 2010 - 08:38 AM

Visual PinMAME Scripting 104 - Mechanics Handlers (TOYS! Part 3 of 3)
--------------------------------------------------------------

Practice practice practice... by looking at code it becomes more familiar.

For Austin Powers I used 3 custom mech handlers.
CODE
    Dim mLaser, mEvil, mDancing 'global variables

    'in Table_init
    Set mLaser=New cvpmMech
    mLaser.MType=vpmMechOneSol+vpmMechReverse+vpmMechLinear
    mLaser.Sol1=21
    mLaser.Length=260
    mLaser.Steps=28
    mLaser.AddSw 43,0,0
    mLaser.AddSw 44,13,27
    mLaser.Callback=GetRef("UpdateLaser")
    mLaser.Start

    'Validity check for saved laser wall position from a previous possible play of the table
    'ie if the nvram was corrupted and it returns a -1 for the position I don't want the table to crash
    If mLaser.Position<0 or mLaser.Position=0 Then
        LaserWalls(0).IsDropped=0
    Else
        LaserWalls(mLaser.Position).IsDropped=0
        End If

    Set mEvil=New cvpmMech
    mEvil.MType=vpmMechOneSol+vpmMechReverse+vpmMechLinear
    mEvil.Sol1=19
    mEvil.Length=50
    mEvil.Steps=2
    mEvil.AddSw 23,0,0
    mEvil.AddSw 22,1,1
    mEvil.Callback=GetRef("UpdateEvil")
    mEvil.Start

    Set mDancing=New cvpmMech
    mDancing.MType=vpmMechOneSol+vpmMechCircle+vpmMechLinear
    mDancing.Sol1=7
    mDancing.Length=40
    mDancing.Steps=4
    mDancing.AddSw 52,3,3
    mDancing.Callback=GetRef("UpdateDancing")
    mDancing.Start

    'update routines are outside table_init in their own subroutines
    Dim DancingWalls
        DancingWalls=Array(DAU1,DAU2,DAU3,DAU4)

Sub UpdateDancing(aNewPos,aSpeed,aLastPos)'animation for Dancing Austin
        DancingWalls(aLastPos).IsDropped=1
        DancingWalls(aNewPos).IsDropped=0
End Sub


Sub UpdateLaser(aNewPos,aSpeed,aLastPos)'animation for Laser
    'Update switch manually for the laser ball shooter if a ball is on the shooter switch for the laser
    If mLaser.Position=0 And BallWaiting=1 Then
        Controller.Switch(45)=1
        BallWaiting=0
    End If
    'validity check for laser wall animation
    If aLastPos>-1 And aNewPos>-1 And aNewPos<27 And aLastPos<27 Then
        LaserWalls(aLastPos).IsDropped=1
        LaserWalls(aNewPos).IsDropped=0
    End If
End Sub

Sub UpdateEvil(aNewPos,aSpeed,aLastPos)'animation for Dr. Evil popup target
    'Only update if the values are different
    If aNewPos<>aLastPos Then
        'validity check for values - if 0 then drop the target, anything else raises the target
        If aNewPos=0 Then
            Target10.IsDropped=1
        Else
            Target10.IsDropped=0
        End If
    End If
End Sub


Hopefully this is beginning to make sense to you by now. Of course there is always Choice 3 - handling it all yourself.
Probably the easiest translation of that is the Dancing Austin Toy. To do that manually you can still use a collection or array for
the walls, or you can manually specify them in your update routine.
A basic brute force method of Dancing Austin would be something like:

CODE
Dim AustinPosition,DancingWalls
AustinPosition=0

DancingWalls=Array(DAU1,DAU2,DAU3,DAU4)

SolCallback(7)="AustinMotor"

Sub AustinMotor(Enabled)
    If Enabled Then
        AustinUpdateTimer.Enabled=0
        AustinUpdateTimer.Enabled=1
    Else
        AustinUpdateTimer.Enabled=0
    End If
End Sub

Sub AustinUpdateTimer_Timer
    DancingWalls(AustinPosition).IsDropped=1
    AustinPosition=AustinPosition+1
    If AustinPosition>3 Then AustinPosition=0
    If AustinPosition=3 Then Controller.Switch(52)=1
    If AustinPosition=0 Then Controller.Switch(52)=0
    DancingWalls(AustinPosition).IsDropped=0
End Sub


Of course you'd need to add a timer object (without the enabled box checked) called AustinUpdateTimer, and make sure its interval is
40ms to match the mechanic handler specification. This code accomplishes everything the mechanic handler does.


As for a toy that can't be simulated with a custom mechanics handler, with the current vbs script package and core.vbs, look at
the High Roller Casino Slot Machine toy.
This toy uses four solenoids to control a stepper motor. We are limited to two solenoids for stepper motors.
The only possible option is to handle it manually, through brute force script work.
The solenoids are 26 for Red, 27 for Green, 28 for Black, and 29 for Blue.
Now this simulation isn't perfect, and perhaps some day I'll get back to this to play with some more to get it working better.
I worked on this for days/weeks - which is a long time for me, and I used two custom mechanics handlers for it with a single callback.

Any game which has solenoids in unreliable condition, like Capcom, will be more difficult to simulate toys with. Capcom's emulation
only has an on and off state for solenoids, however the rom has a solenoid power setting it can change at will. A motor running at
2 volts will run slower than one at 5 volts could. We currently only have access to an on or off state, so you get the idea.
In those cases you can use light state checks, or other queries to get the desired result.

This wraps up the current 'overview' tutorial for mechanics handlers. Thanks for your patience.
The next tutorial will be on shortcuts within the scripting system.

Build a fire, vipers love the heat.


#4 wtiger

wtiger

    Pinball Fan

  • VIP
  • 1,148 posts
  • Location:Los Angeles, CA

  • Flag: United States of America

  • Favorite Pinball: Junkyard



Contributor

Posted 31 March 2010 - 02:11 AM

Destruk,
Thanks for taking the time to put this together. It looks like a lot of valuable information there. I did not read it yet (I saved it for offline browsing). I'll be reading through it from start to finish this weekend!

#5 jpsalas

jpsalas

    Grand Schtroumpf

  • VIP
  • 7,171 posts
  • Location:I'm Spanish, but I live in Oslo (Norway)

  • Flag: Norway

  • Favorite Pinball: I like both new and old, but I guess I prefer modern tables with some rules and goals to achieve.



Posted 31 March 2010 - 03:31 AM

Thanks destruk! That clears off a few things smile.gif

JP

If you want to check my latest uploads then click on the image below:

 

vp.jpg

 

WIP? Cobra, Nuova Bell and Playbar tables, thanks to akiles50000 redrawings


#6 melon

melon

    Enthusiast

  • VIP
  • 326 posts
  • Location:Spain

  • Flag: Spain

  • Favorite Pinball: Addams Family



Posted 06 April 2010 - 08:11 PM

Thank you Destruk for writing these tutorials.
This one (and the other ones too) has been much helpful for me, as I'm new making VPinMAME table recreations.
This is a VERY important information, a must read for all the table makers, I think.
Thanks

cycloneMini2.png TafMini2.png FishTalesMini2.png spaceShuttleMini2.png bk2kmini.png GetawayMini.png


#7 MRCMRC

MRCMRC

    Enthusiast

  • Members
  • PipPipPip
  • 196 posts

  • Flag: Spain

  • Favorite Pinball: Canasta 86

Posted 12 March 2012 - 04:15 PM

Thanks for the info, Destruk. I have one question:

I'm trying to recreate train enconder in Cactus Canyon. The encoder switch seems to be an opto with a wheel similar to the one on the PC mouses. So I think I must pulse the switch at a constant rate when the train moves.

I've done that pulsing the switch every other step, but I think I can improve the the emulation using vpmMechLengthSw. But since .AddPulseSw and .AddSw use step parameters, not time parameters, I can't figure out how to put all them togheter.

Can you provide an example?

Thanks in advance!

#8 destruk

destruk

    VPF Veteran

  • VPF Staff
  • 6,307 posts
  • Location:Colorado Springs, CO

  • Flag: United States of America

  • Favorite Pinball: Ultrapin!



Posted 12 March 2012 - 08:52 PM

Encoder switches are used in the Johnny Mnemonic glove, and the Corvette drag strip - so probably look at those or other cactus canyon tables which have a working train in them already.

Build a fire, vipers love the heat.