Skip to content

Commit

Permalink
Improved things here and there
Browse files Browse the repository at this point in the history
  • Loading branch information
WaluigiBSOD committed Nov 6, 2023
1 parent 2b4b55e commit 39d03e0
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 48 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ JavaScript port of [Dr. Mario 64 Password Encoder/Decoder Tool](https://github.c

## How to use

1. Play Dr. Mario 64 and, after winning or losing a Classic, Marathon or Score Attack game, press **Z + R + L + D-Pad Left** when the menu is on-screen.
2. Write down the displayed password
1. Play Dr. Mario 64 and, after either winning or losing a Classic, Marathon or Score Attack game, press **Z + R + L + D-Pad Left** when the menu is on-screen.
2. Write down the displayed password.
3. Open [https://waluigibsod.github.io/dm64-password-decoder/](https://waluigibsod.github.io/dm64-password-decoder/).
4. Enter the password (e.g. `E5HQ3E80B03JA5316R1F`).
5. Read the decoded info.

More info [on TCRF](https://tcrf.net/Dr._Mario_64#Passwords).

## Program

Both this program and [Dr. Mario 64 Password Encoder/Decoder Tool](https://github.com/WaluigiBSOD/dm64-password-tool) were written using the original source code of the game that leaked in July 2020 as reference.

The original implementation of the password encoding algorithm inside the source code of the game can be found at `bbgames.7z\bbgames.tar\d1\routefree\bbgames\depot\dm64\src\passwd.c`, for some reason the password decoding algorithm is absent but it can be easily obtained by inverting the encoding one.

## License

The source code is released under the GNU General Public License v 3.0 (see [LICENSE](https://github.com/WaluigiBSOD/dm64-password-decoder/blob/master/LICENSE) in the root of the repository for a copy of the license and for more information).
Expand Down
5 changes: 5 additions & 0 deletions css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ h2 {
display: table-cell;
}

hr {
color: #FFFFFF;
}

input.code {
font-family: "Lucida Console", monospace;
text-align: center;
transform: scale(3);
}
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ <h2 id="version" onmouseenter="_SetVersionDate()" onmouseleave="_SetVersion()">.

<div align="center" class="main">

<input type="text" autocomplete="off" id="code" class="code" size="40" maxlength="20" onclick="_ResetInput()" oninput="_CheckPassword()" value=""></input>
<input type="text" autocomplete="off" id="code" class="code" size="25" maxlength="20" onclick="_ResetInput()" oninput="_CheckPassword()" value=""></input>
<p id="error" class="error"><br>Enter password</p>

<table id="result" class="result" style="display: none;">
Expand Down
38 changes: 31 additions & 7 deletions js/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,30 +224,54 @@ const FrameCountMaximum = 1023;
//
// 0: Caption
// 1: Caption ID (optional)
// 2: ID of the area to be filled by the decoder
// 2: Area ID (to be filled by the decoder)

const ResultEntries = [
[
"Mode", "", "mode"
"Player Name", // Caption
"", // Caption ID
"name" // Area ID
],

[
"Level", "level-text", "level"
"", // Caption
"", // Caption ID
"" // Area ID
],

[
"Speed", "", "speed"
"Score", // Caption
"", // Caption ID
"score" // Area ID
],

[
"Score", "", "score"
"Time", // Caption
"", // Caption ID
"time" // Area ID
],

[
"Time", "", "time"
"", // Caption
"", // Caption ID
"" // Area ID
],

[
"Player Name", "", "name"
"Mode", // Caption
"", // Caption ID
"mode" // Area ID
],

[
"Level", // Caption
"level-text", // Caption ID
"level" // Area ID
],

[
"Speed", // Caption
"", // Caption ID
"speed" // Area ID
]
]
50 changes: 26 additions & 24 deletions js/decoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ function _DecodePassword(Password = "") {
var FrameCountX = 0;
var FrameCountY = 0;

var CheckSum = 0;
var CheckSumLastTwoBits = 0;
var TestCheckSum = 0;
var Checksum = 0;
var ChecksumLastTwoBits = 0;
var TestChecksum = 0;

var GameMode = 0;
var Level = 0;
Expand All @@ -47,7 +47,7 @@ function _DecodePassword(Password = "") {
var Time = 0;
var FrameCount = 0;

var Name = [0,0,0,0];
var Name = Array(4).fill(0);

var TemporaryX;
var TemporaryY;
Expand Down Expand Up @@ -75,6 +75,7 @@ function _DecodePassword(Password = "") {

if (TemporaryX > -1) {
PasswordChunkHigh |= TemporaryX << 25;

if (i < 6)
PasswordChunkHigh >>= 5;
} else {
Expand All @@ -91,6 +92,7 @@ function _DecodePassword(Password = "") {

if (TemporaryX > -1) {
PasswordChunkMedium |= TemporaryX << 25;

if (i < 12)
PasswordChunkMedium >>= 5;
} else {
Expand All @@ -107,6 +109,7 @@ function _DecodePassword(Password = "") {

if (TemporaryX > -1) {
PasswordChunkLow |= TemporaryX << 25;

if (i < 18)
PasswordChunkLow >>= 5;
} else {
Expand All @@ -116,7 +119,7 @@ function _DecodePassword(Password = "") {
}
}

// Constant (frame count, modulo 1024)
// Randomization Constant (frame count, modulo 1024)

FrameCountConstant = TableMaskFrameCountLower[FrameCountX] ^ TableMaskFrameCountUpper[FrameCountY];

Expand All @@ -126,11 +129,11 @@ function _DecodePassword(Password = "") {

// Constant (checksum)

CheckSumLastTwoBits = (PasswordChunkHigh >> 28) & 0x3;
ChecksumLastTwoBits = (PasswordChunkHigh >> 28) & 0x3;

PasswordChunkHigh ^= TableMaskHigh[CheckSumLastTwoBits];
PasswordChunkMedium ^= TableMaskMiddle[CheckSumLastTwoBits];
PasswordChunkLow ^= TableMaskLower[CheckSumLastTwoBits];
PasswordChunkHigh ^= TableMaskHigh[ChecksumLastTwoBits];
PasswordChunkMedium ^= TableMaskMiddle[ChecksumLastTwoBits];
PasswordChunkLow ^= TableMaskLower[ChecksumLastTwoBits];

// Time

Expand All @@ -152,9 +155,9 @@ function _DecodePassword(Password = "") {
Speed = PasswordChunkLow & 0x3;
PasswordChunkLow >>= 2;

// CheckSum (1/2)
// Checksum (1/2)

CheckSum = PasswordChunkLow & 0xFF;
Checksum = PasswordChunkLow & 0xFF;

// Level (2/2)

Expand All @@ -179,23 +182,22 @@ function _DecodePassword(Password = "") {
Score = PasswordChunkHigh & 0xFFFFF;
PasswordChunkHigh >>= 20;

// CheckSum (2/2)

CheckSum = (CheckSum << 2) | (PasswordChunkHigh & 0x3);
// Checksum (2/2)

CheckSum &= 0x3FF;
Checksum = (Checksum << 2) | (PasswordChunkHigh & 0x3);
Checksum &= 0x3FF;

// Test CheckSum
// Test Checksum

TestCheckSum = GameMode + Level + Speed;
TestCheckSum += (Score & 0x3FF);
TestCheckSum += ((Score >> 10) & 0x3FF);
TestCheckSum += (Time & 0xFF);
TestCheckSum += ((Time >> 8) & 0xFF);
TestCheckSum += Name[0] + Name[1] + Name[2] + Name[3];
TestCheckSum &= 0x3FF;
TestChecksum = GameMode + Level + Speed;
TestChecksum += (Score & 0x3FF);
TestChecksum += ((Score >> 10) & 0x3FF);
TestChecksum += (Time & 0xFF);
TestChecksum += ((Time >> 8) & 0xFF);
TestChecksum += Name[0] + Name[1] + Name[2] + Name[3];
TestChecksum &= 0x3FF;

if (CheckSum == TestCheckSum) {
if (Checksum == TestChecksum) {
// Mode

if (GameMode == GameModeClassic)
Expand Down
20 changes: 17 additions & 3 deletions js/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,27 @@

const Title = "Dr. Mario 64 Password Decoder";

const Version = "1.4.2";
const VersionDate = "14 November 2022";
const Version = "1.5";
const VersionDate = "6 November 2023";

// Functions

function _SetTitle() {
document.getElementById("title").innerHTML = Title;
var SplitTitle = Title.split(" ");

var FinalTitle = "<i>";

for (var i=0;i<SplitTitle.length;i++) {
if (SplitTitle[i].toLowerCase().search("password") > -1)
FinalTitle += "</i>";

FinalTitle += SplitTitle[i];

if (i + 1 < SplitTitle.length)
FinalTitle += " ";
}

document.getElementById("title").innerHTML = FinalTitle;
}

function _SetVersion() {
Expand Down
14 changes: 3 additions & 11 deletions js/result.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@

// Functions

function _ResultTableReset() {
var retELEMENT = "";

return retELEMENT;
}

function _ResultTableAddBlankRow() {
var retELEMENT = "<tr><td></br></td></tr>";

Expand All @@ -34,9 +28,9 @@ function _ResultTableAddColumn(Caption, CaptionID, EntryID) {
var retELEMENT = "<tr>";

if (CaptionID.length > 0)
retELEMENT += "<td id=\"" + CaptionID + "\">" + Caption + ": </td>";
retELEMENT += "<td id=\"" + CaptionID + "\">" + Caption + ":&emsp;</td>";
else
retELEMENT += "<td>" + Caption + ": </td>";
retELEMENT += "<td>" + Caption + ":&emsp;</td>";

retELEMENT += "<td id=\"" + EntryID + "\"></td>";

Expand All @@ -56,9 +50,7 @@ function _GenerateResultTableSkeleton() {
CurrentElement = ResultEntries[i];

if (CurrentElement.length != 3 || CurrentElement[0] == "") {
TableBody = _ResultTableReset();

break;
TableBody += "<tr><td colspan=\"2\"><hr></td></tr>";
} else {
CurrentElement[0].trim();
CurrentElement[1].trim().toLowerCase();
Expand Down

0 comments on commit 39d03e0

Please sign in to comment.