Dr. Mario virus placement

Thread in 'Research & Development' started by IoannesPaulus, 3 Aug 2012.

  1. Attached is the source code for my reverse-engineered C version of SNES Dr. Mario's virus randomizer. The code directly corresponds to how the original code worked, adapted to C. I haven't analyzed it closely, nor compared it to the NES randomizer; someone else can do that. The archive also includes an IPS patch, to be applied to an SMC format ROM, that disables the randomizer being run every frame; I had to disable it, so that my code could be verified to be correct against the original, and I'm including the patch so others can verify for themselves.

    Attached Files:

    Boxes_DC likes this.
  2. Thanks so much @nightmareci for your work here. It started all of my adventures into NES Dr. Mario disassembly, which are continuing (I need to organize everything and make a post somewhere). I've made a mod for the NES version that allows you to choose a seed value in the level select screen and play a specific seed, with 0000 and 0001 falling back to the default behavior since they're invalid with the LFSR. The seed that was used to generate the current bottle is also shown while playing so that you can go back and replay it if desired. The UI is a bit rough (it doesn't show that you've gone down to the seed selection), but pressing <LEFT> and <RIGHT> will change the digit that's selected and <SELECT> will change the digit that is currently selected (also not shown in the UI yet). I've included the patch here for all to try out. I streamed while playing a demo and giving instructions on how to use it here.

    We also have a Discord where we discuss all things Dr. Mario (mostly the NES version), with a special channel just for custom tools/hacks. https://discordapp.com/invite/7fqvK4n

    Attached Files:

  3. Thank you, I'll integrate that into my clone today! Also you're credited in the credits :)
  4. I'm running the program with all 65536 seeds for levels 20-29 to see if it locks up. Level 20 has no issues, but in Level 21 there are 12 separate seeds that cause a lockup in "GenVirus()"

    - 0x074E //Gets stuck on 85
    - 0x28b8 //Gets stuck on 87
    - 0x3cab //Gets stuck on 86
    - 0x3f3a //Gets stuck on 87
    - 0x513f //Gets stuck on 86
    - 0x9325 //Gets stuck on 86
    - 0x933c //Gets stuck on 87
    - 0x9d3e //Gets stuck on 87
    - 0xa06a //Gets stuck on 87
    - 0xad35 //Gets stuck on 87
    - 0xb867 //Gets stuck on 87
    - 0xe13f //Gets stuck on 87

    For seed 0x074E, I viewed the WIP bottle and all the remaining empty spaces were unusable (Placing a virus there of any colour would have broken a placement rule). I assume the other 11 seeds locked up for the same reason.

    I assume the higher the level, the more lockup-seeds will appear. Are you aware of any restrictions on the value of the seed? I see in main's "GenVirus()" loop there's a comment saying the seed is randomised some number of times or not at all. What determines the number of seed randomisations?

    In the mean time I'm going to try and dig into the rest of this code to understand how this new system works.

    EDIT: I see a problem with the code. The variable "numVirusGenAttempts" is always zero. If it did increment then eventually the function would exit (Although it wouldn't have all the viruses it could have had) and hence the softlock wouldn't happen. There might be more pieces missing, I'm still trying to understand some of the player variables. I'll update here if I find anything else.
    Last edited: 23 Jan 2020
  5. I've updated the archive in my previous post for the SNES randomizer, fixing the bug you noted, and another in ValidVirusPos, where it should return false when the first if-condition fails, and did some refactoring.

    The game runs RealRand (a function that Rand calls, with Rand doing nothing else) some random number of times every frame, 0 or more. The number of times isn't governed by an explicit algorithm; it just keeps running the randomizer after a frame has been updated, so the number of times RealRand is run is proportional to how many CPU cycles remain after a frame update.
    Last edited: 23 Jan 2020
  6. Thanks for that, its no longer softlocking. On level 23 I noticed only roughly 80% of the seeds were successful (The requested number of viruses are present). So I ran some more tests that showed something promising.

    - I set the level to 23 (96 viruses)
    - I run all seeds for level 23 "k" times
    - For the current value of "k" I call Rand() that many times before every GenVirus() call
    - I set k to go from 0 to 100 and got the number of successful seeds for each run

    My results are as attached, but I can tell you I had the most success with 15 calls of rand which produced 65013 successful seeds out of 65536 (Thats a 99.3% success rate) or 523 bad seeds. For levels 0 - 22, every seed is successful using this method.

    The catch is for lower levels, they look rather bad with most of the viruses one of two columns, so I recommend only doing these 15 Rand() calls if you are on level 21+ (Lv 21 is the first level that would normally have some bad seeds). I haven't tested this too much yet, but levels 21+ look good with this enhancement.

    In case my description wasn't clear, here's how you add the enhancement. In main() go to the 3rd for loop and add this code just before the GenVirus() call (Note the "k" stuff was just a part of the previous test, not the "better seeds" solution so don't worry about that):
    if(Players[Current_Player].virusLevel > 20){    //Only do this for later levels where its required
        for(j = 0; j < 15; j++){    //Runs 15 times
    To fix the remaining 523 bad seeds, you could add an array of all the seeds and if your initial seed is one of them then re-roll. Thanks again nightmareci for your research :D

    Attached Files:

  7. I'm not sure where else to say this, but this page has some issues https://tetris.wiki/Dr._Mario

    Specifically the rotation section. It doesn't explicitly state you can rotate both clockwise and anti-clockwise (That might be obvious to some, but I haven't played the real Dr M in ages so I didn't know) and then in its wall-kick examples it uses clockwise and anti-clockwise rotations interchangeably. For months I've been wondering why my vertical wall kick felt off and this is why.

    I wanted to edit this to make these things clear, however I can't make an account for the wiki, the CAPTCHA is literally broken (As seen below). Sometimes it did generate questions I could read, but even then it always said I was wrong even though I'm certain my answers were right. Can someone with an account fix this so others don't get confused in the future?

    (EDIT: I've been informed that particular question isn't bugged. The answer is "L" and apparently those are the tetris shape pieces...)
    Last edited: 11 Feb 2020

Share This Page