Post Reply 
 
Thread Rating:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Removing randomization from Dracula Mystery
02-13-2012, 05:12 PM
Post: #1
Removing randomization from Dracula Mystery
There's already a way in the adjustments to remove awards other than points from Dracula's mystery award, but there needs to be a tournament mode created to ensure the points award is always the same for all players - how to go about finding this type of award? Is there a random seed somewhere that the game uses to determine randomness for this type of award?
Find all posts by this user
Quote this message in a reply
02-15-2012, 04:49 PM
Post: #2
RE: Removing randomization from Dracula Mystery
In the 'STTNG Video Mode' thread I talk about the callback functions which WPC uses. For BSD we can first manually trigger each of the callback functions until you get the one that handles the mystery shot. Once you do that, you can trace through the mystery shot code and see how it works.

WPC code has a "GetRandomNumber" function which the caller can pass in the max number to return. So it basically says "give me a random number between 0 and x".

I'm not sure if simply skipping the call to GetRandomNumber() would be sufficient. I suspect you'd need to find some unused ram to store the "NextMysteryAward" for each player, ensure these get initialized at game start, and that the correct player's award gets referenced each time. Game might already store the "LastMysteryAward" for each player which you could use for this hack. They probably store the last awarded value for each player to ensure they don't give too many specials or extra balls with the mystery award.

This is definitely doable, just takes some time and patience. Later as I have more free time I'll dig into BSD and give some more specific details if you haven't found the mystery award code yet.
Find all posts by this user
Quote this message in a reply
02-17-2012, 06:21 AM
Post: #3
RE: Removing randomization from Dracula Mystery
(02-15-2012 04:49 PM)mrglee Wrote:  In the 'STTNG Video Mode' thread I talk about the callback functions which WPC uses. For BSD we can first manually trigger each of the callback functions until you get the one that handles the mystery shot. Once you do that, you can trace through the mystery shot code and see how it works.

Referencing the STTNG video mode thread I find that in BSD the lookup table routine is $8590 - the mystery shot gives a value of $1f when trapping, however, so do a bunch of other switches; clearly, there's something else going on to select the correct function. Adding a credit does $0c and if you change the $0c to $1f, the machine reboots. It falls back from the JSR $c7e3 without doing anything up on the display.
Find all posts by this user
Quote this message in a reply
02-17-2012, 06:48 PM
Post: #4
RE: Removing randomization from Dracula Mystery
Okay I see what you're saying. The functions that are comparable to those mentioned for STTNG, in Drac_l1 are at $8590 which calls $c7e3, using callback table pointer 0x81d4. Setting breakpoint at $c7e3 and hitting the mystery shot reveals it's callback 0x1f, but there's something special about this because if you manually put in 0x1f at coin-up, it crashes the game.

The 0x81d4 table points to $65f9,3d where entry 0x1f is: 50 2c f8 ed ff. This would imply the callback address is in non-banked memory at $f8ed, however setting a breakpoint there shows it gets called for other things as well, so the drac_l1 doesn't quite follow the IJ and STTNG as far as the straightforward hacking of the callback function.

So lets take another approach. It's likely the mystery shot utilizes the getRandomNumber() function. In IJ_L7 it starts out like this:

A7A1: 34 04 PSHS B
A7A3: B6 17 A1 LDA $17A1
A7A6: BA 17 A2 ORA $17A2
A7A9: 26 06 BNE $A7B1
A7AB: 7C 17 A1 INC $17A1
A7AE: 7A 17 A2 DEC $17A2
A7B1: F6 17 A3 LDB $17A3
A7B4: 86 03 LDA #$03
A7B6: 3D MUL
A7B7: CB 11 ADDB #$11
A7B9: B6 17 A1 LDA $17A1

So searching drac_l1 I find its getRandomNumber() is at ROM offset 0x7a739 which corresponds to a WPC address of $a739. When this function is called, the A register has the maximum random number that's being requested. So I start up a game and launch the ball then set breakpoint at $a739. Right away I get a bunch of breakpoints, so the game s/w is doing a lot of random number calls. Carefully hit 'esc' and then 'M' to try to get the Mystery shot to trigger the getRandomNumber() function.

I notice I got a breakpoint at $a739 with value 0x64 in the A register, this one might be due to the 'M' press, although this would mean the mystery code asked for a random number from 0-100. Tracing out the end of this function reveals it was called from $577a,35.

Hitting 'esc' again reveals yet another immediate breakpoint at getRandomNumber() with 0x64 in A register. Also the DMD shows the mystery shot animation is starting. This second call to getRandomNumber() was called from $577a,35 also.

Hitting 'esc' again reveals yet a 3rd immediate breakpoint at getRandomNumber() with 0x64 in A register. Again, the mystery shot is still starting. This one was also called from $577a,35.

Hitting 'esc' again reveals a 4th immediate breakpoint at getRandomNumber() with 0x08 in A register. This was called from $5714,35.

Hitting 'esc' again finally lets the mystery shot proceed. In my case the last random number call return 7 which awarded 5,000,000 points. So it's likely the call to getRandomNumber() from $5714,35 was the one that determined what to award the player. (Later I realize the call from $5714,35 was only to determine one of 8 POINTS awards. So the previous calls to get random number from 0-100 must help determine non-point awards.)

So I clear breakpoints, and start over a new game, and then set breakpoint at $5714. Since there are multiple ROM banks, we want to ignore any hits at $5714 when value of $13 is not value 0x35 (drac_l7 stores current ROM bank here). We want to break at $5714,35 and force the returned value to different values to see what happens. So I run code to $5717 and manually change A register to different values and have the following results (I changed A prior to the INCA instruction gets hit):
00 == 100,000 points
01 == 250,000 points
02 == 500,000 points
03 == 750,000 points
04 == 1,000,000 points
05 == 2,000,000 points

So it appears all of the hits above have something to do with mystery shot. You might want to put breakpoint at $5714,35 and trace through the code to figure out how it works. While tracing code around $5714,35 I'd use the DASM command to export 4000-7fff to a text file and disassemble it from there.

I hope this helps.
Find all posts by this user
Quote this message in a reply
02-18-2012, 07:04 AM (This post was last modified: 02-18-2012 07:10 AM by RalphButler.)
Post: #5
RE: Removing randomization from Dracula Mystery
(02-17-2012 06:48 PM)mrglee Wrote:  So I clear breakpoints, and start over a new game, and then set breakpoint at $5714. Since there are multiple ROM banks, we want to ignore any hits at $5714 when value of $13 is not value 0x35 (drac_l7 stores current ROM bank here). We want to break at $5714,35 and force the returned value to different values to see what happens. So I run code to $5717 and manually change A register to different values and have the following results (I changed A prior to the INCA instruction gets hit):
00 == 100,000 points
01 == 250,000 points
02 == 500,000 points
03 == 750,000 points
04 == 1,000,000 points
05 == 2,000,000 points

So it appears all of the hits above have something to do with mystery shot. You might want to put breakpoint at $5714,35 and trace through the code to figure out how it works. While tracing code around $5714,35 I'd use the DASM command to export 4000-7fff to a text file and disassemble it from there.

I hope this helps.

Yes that does help a lot. Couple of things I discovered, is that the call from 5714 actually goes to $a76f - making it a bit easier to trace as that's just one call to A739's random code. At any rate, the code from 5114 is:

5714: JSR $a76f
5717: inca
5718: sta $9b

etc. which is definitely the mystery award. I have all the "other" mystery awards set to 00% in the adjustments, so points is always what's awarded anyway.

I find that changing 5714 to: lda #$00, nop making the mystery random value always 00, it starts at 100k as expected, however, repeated shots to the mystery hole increase this value in a progression, so the game is keeping track of the last mystery award and making it more. I've had it start at 250 but usually at 100k; 100k, 250k, 500k, 750k, and then it starts to become more random again. But it's always a progression. (sometimes it awards 5 million instead of 1 million, making the progression 5, 10, 15, 20, back to 100k, instead of 1, 2, 4, 5) Changing the lda #$00 to lda #$01 does the same thing but starts at 250k; however, it also crashes when you get far enough into the sequence, and I have had a pause where I wasn't pushing the right inlane-mystery over and over, where it started over at 100k.

It is less random at this point - you're not going to get 20 million off the bat for no reason, at least. It resets for the next player too, and comes back for the first player (so if player 1 stopped at 500k, their next award is going to be 750k regardless of what player 2 stopped at).

I suppose on a related tact, preventing the right inlane from lighting the mystery at all might be acceptable. There is a mystery timer adjustment but setting it to zero makes it not time out at all.

I pick up my Dracula machine next week sometime so I can try it live in the machine instead of just in pinmame, but I know there's tons of stuff to fix first.

Thanks for your help, any other ideas I'm open to them. Oddly also in my version of pinmame (0.63 IIRC) the disassembly of the banked code just shows NEG $00, although the opcodes are there and correct. Not a huge problem I just used TRACE to dump the code instead.

Oh, and I just tried to change the code to remove the INCA in case that was a factor - did lda #$00, lda #$00 for that sequence. Did it as a NOP and it just made it completely random again. Since I do have the trace from a full set of what the random code is doing I can analyze it a bit. Still learning WPC architecture so slow going....
Find all posts by this user
Quote this message in a reply
02-18-2012, 07:59 AM
Post: #6
RE: Removing randomization from Dracula Mystery
I suspect the 3 calls to getRandomNumber() which used value 100, must have been related to those adjustments that allow you to configure a percentage for the non-points awards.

What exact behavior do you want? Do you want it to award a fixed award every time or do you want it to award some increasing points value each time (and yes, same thing for each player as they hit the Mystery shot).

We can also wedge in a call to get the tournament mode setting, and only award your hacked in value when tournament mode is set to Yes, then award truly random value when tournament mode is set to No. You would do this by inserting a call to your new code at unused area (in same bank 0x35) where it does what you want and jumps back.

Congrats on getting the BSD. I have that pin also and find it to be my most challenging pin especially with the lightning flippers installed.
Find all posts by this user
Quote this message in a reply
02-18-2012, 08:15 AM
Post: #7
RE: Removing randomization from Dracula Mystery
(02-18-2012 07:59 AM)mrglee Wrote:  I suspect the 3 calls to getRandomNumber() which used value 100, must have been related to those adjustments that allow you to configure a percentage for the non-points awards.

What exact behavior do you want? Do you want it to award a fixed award every time or do you want it to award some increasing points value each time (and yes, same thing for each player as they hit the Mystery shot).

We can also wedge in a call to get the tournament mode setting, and only award your hacked in value when tournament mode is set to Yes, then award truly random value when tournament mode is set to No. You would do this by inserting a call to your new code at unused area (in same bank 0x35) where it does what you want and jumps back.

Congrats on getting the BSD. I have that pin also and find it to be my most challenging pin especially with the lightning flippers installed.

Well, with the code hack I posted making the return 00 no matter what, it already does the increasing value. My personal preference is to not light the mystery at all when tournament mode is on, negating the need to mess with the results.

I did actually lose a match in a tournament on dracula because I got 500k mystery and the other guy got 20 million and our scores were less than 4 million apart. It's not always a factor but annoying when one player gets the break through luck instead of skill.

Is there a table of switch routines in WPC like the earlier systems have? Could approach it from either angle - right inlane routine or mystery hole switch routine. Since mystery is lit automatically at game start the hack to make it 100k or 250k would probably be ok, if there were no other way to light it. Would be nice to remove the auto mist lit on ball 3 too if you hadn't earned it.
Find all posts by this user
Quote this message in a reply
02-18-2012, 09:39 AM
Post: #8
RE: Removing randomization from Dracula Mystery
Yes every WPC game has a master switch table which contains a callback address to run code to handle each switch. I thought I posted about it once but I cannot find such post. Such switch-table was how I found all of the flipper-button combination easter eggs.

Each callback then checks the states of things and reacts accordingly. For example when the mystery shot switch is hit, it probably checks to make sure a game is presently in progress, and that the mystery award was lit, then if so, runs though the mystery-award stuff we have been talking about.

I thought I had made a post about the switch table but didn't see it, here's how it start in IJ_L7:

;----------------------------------------;---------------------------------------------------------
;
; PlayfieldSwitchTable[]
;
; TablePointer07, From $81CB table pointers
;
;
;
; This table is loaded during switch matrix reading from $95DB.
; This is loaded for switch indexes 0x01-0x49
;
; Each 11-byte entry for each switch below has the following format:
; ------------------------------------------------------------------
; 01 02 03 04 05 06 07 08 09 0A 0B
;
;
; 01 02
; 03 04 05 ; $XXYY,ZZ Address in ROM
; 06 07
; 08 ; This is a flag byte with the following bit-flag definitions for this switch
; ; 11111111
; ; ||||||||
; ; |||||||\-- 0x01 bit.
; ; ||||||\--- 0x02 bit.
; ; |||||\---- 0x04 bit.
; ; ||||\----- 0x08 bit.
; ; |||\------ 0x10 bit.
; ; ||\------- 0x20 bit. When set, we'll NOT include this in the every 90-balls switch error test.
; ; |\-------- 0x40 bit.
; ; \--------- 0x80 bit.
; ;
; ;
; 09
; 0A
; 0B
;
;
;
;
;
6DE9: 00 49 ; This table has entries for up to switch index value 0x49
6DEB: 0B ; Each entry is 0x0B in length
;
;
6DEC: 04 04 ; SwitchTableEntry00, 0 Invalid Switch Index/Reference
6DEE: 99 28 FF ; $9928,FF
6DF1: 3C 00 20 ;
6DF4: 00 00 00 ;


Note, also there's a bit that simply defines whether the switch participates in the credit-dot testing.

The first switch entry is a null which jumps back to $9928 in IJ_L7 this just returns back to normal processing. In fact all switch handler code will end up jumping to $9928 when they're done doing whatever they do. The drac_l1 will have a different address.

So searching drac_l1 for: 00 49 0b 04 04, reveals the switch table is at ROM offset 0x74e82, and the "done" address in drac_l1 is $990e (not $9928 as in IJ_L7).

I see the mystery switch is the last row of column 5. I'll call this index 40.
I know there are 9 entries in the table prior to the switch matrix stuff (for coin door things).
So I do the math to get to the 49th entry...

0x74e82 = start of switch table header
0x74e85 = start of swtich table entries, entry 0 (null entry)
0x75095 = address of 49th table entry, mystery switch

0x75095: 00 04 46 35 30 3c 00 08 80 00 04 <--- mystery switch callback is $4635,30

So you can set a breakpoint at $4635 and trace code there when mystery shot is hit.
Need to ignore any breakpoints that get hit when $13 contains anything other than 0x30.

Next you may wonder about determining the tournament mode setting.
There is a function you can call to look up a game setting and compare it to a particular value.
You can then check the C-bit to know if the setting matched the particular value.

In IJ_L7 this function start like the following:
86AE: 34 36 PSHS Y,X,B,A ; Push Y,X,B,A
86B0: 32 7F LEAS $FFFF,S ; Decrement stack pointer to make an extra temporary byte for us to use
86B2: AE 67 LDX $0007,S ; Load X with the 2-byte parameter to this function call
86B4: EC 81 LDD ,X++ ; Dereference the parameter, load D with the 2 bytes that were passed into this function.
86B6: AF 67 STX $0007,S ; Fixup stack so we RTS to the correct location
86B8: E7 E4 STB ,S ; Store the 2nd read in byte (dereferenced above) into the temporary byte
; on the stack

Searching for the byte pattern in drac_l1 reveals this function is located at ROM offset 0x78698 which is WPC address $8698.
So you can play around with this function to eventually determine what number represents tournament mode.
For example find any place in the code that has: BD 86 98 xx yy. The xx is the adjustment number and yy is the value to compare against. Your hacked code will eventually make a call with: BD 86 98 xx 01 to see if the tournament mode matches value 01 (or you can compare against 00), then BCS or BCC depending on if you want to branch when tournament mode is Yes or No.

I'm actually researching another WPC project this weekend so I should be around for any other questions.
Find all posts by this user
Quote this message in a reply
02-18-2012, 11:38 AM
Post: #9
RE: Removing randomization from Dracula Mystery
OK, got it. Found exactly where the mystery hole branches to award mystery or not, regardless of status of the lamp. I suppose in a tournament you could just remove the lamp physically although it would be slick to just have it linked in with the code. How/where are audits/adjustments stored in WPC? You could simply read the value from nvram directly, right vs. doing the function calls, etc.?

There a ton of room in bank 30 to add stuff. And to think I was worried about finding space to insert a routine. Waiting to hear back from the players to see what kind of result they prefer.... either nothing or the progression.
Find all posts by this user
Quote this message in a reply
02-18-2012, 04:03 PM
Post: #10
RE: Removing randomization from Dracula Mystery
I wouldn't try to read nvram directly. I'd make sure it uses existing WPC code for reading adjustments.

There's quite a bit to adding a new adjustment but it can be done. As my spare time frees up I'd like to write a thread about it, or just compile a big .doc with all of the details that have been thrown around in the different threads.
Find all posts by this user
Quote this message in a reply
Post Reply 


Forum Jump:


User(s) browsing this thread: 2 Guest(s)