
This little extra goodie is nothing more than a clock program with a few cute animations for each character, along with a little message to you, the player. My first order of business was to modify the "splash screen" (logo, text, etc.), which was easy enough in CrystalTile.

I was also able to use CrystalTile to find the font sheet that the VMU program uses to render text. Despite text being extremely limited, the developers actually took the time to write their own text-rendering routine, rather than just use separate 48x32px 1bpp images for each instance of text. Truthfully, I'm not 100% sure if they wrote that code themselves, or it came from SEGA. Based on SEGA's VMU technical documentation, it would appear that they wrote something unique, and not templated.

Funnily enough, the ill-fated (or still to be seen?) Dreamcast game "Elysian Shadows" managed to deliver something very useful for this endeavor: ElysianVMU. This little VMU emulator actually features a RAM/ROM debugger/editor.

Furthermore, I was able to disassemble the Sanyo LC8670 assembly (similar to LC86104C/108C) using this processor for Ghidra and LCdis. However, after making all of that progress, I was still unable to track the archaic assembly to determine where the text strings were stored. Even guessing at the 1-byte representation of each font tile, and then searching for a known order, yielded no results.
Eventually, I decided to write a little program to do some brute-forcing. And yes, that's right folks, that's Perl you're seeing. Kindly hold your comments and critiques, for I simply do not care

Code: Select all
#!/usr/bin/perl
use strict;
use File::Path;
use String::HexConvert ':all';
my $filename = "NAKO_NAK.VMS";
my $file_size = (stat "$filename")[7];
open my $file_handle, '<:raw', $filename;
for(my $i = 1; $i < $file_size - 5; $i ++)
{
my $byte = &read_bytes_at_offset($file_handle, 1, $i - 1);
my $byte_plus_one = &read_bytes_at_offset($file_handle, 1, $i);
my $byte_plus_two = &read_bytes_at_offset($file_handle, 1, $i + 1);
my $byte_plus_three = &read_bytes_at_offset($file_handle, 1, $i + 2);
my $byte_plus_four = &read_bytes_at_offset($file_handle, 1, $i + 3);
my $byte_plus_five = &read_bytes_at_offset($file_handle, 1, $i + 4);
if($byte eq $byte_plus_five &&
$byte_plus_three eq $byte_plus_four &&
$byte_plus_one ne $byte_plus_two &&
$byte_plus_one ne $byte &&
$byte_plus_one ne $byte_plus_three &&
$byte_plus_one ne $byte_plus_five &&
$byte_plus_two ne $byte &&
$byte_plus_two ne $byte_plus_three &&
$byte_plus_two ne $byte_plus_five &&
($byte ne "20" && $byte ne "00" && $byte ne "ff"))
{
print "BYTE: $byte\n";
print " +5: $byte_plus_five\n";
print " LOC: " . ($i - 1) . " (decmical)\n";
print "===========================\n";
}
}
close($file_handle);
# arg 0 = file handle
# arg 1 = bytes to read (length)
# arg 2 = offset at which to read
sub read_bytes_at_offset
{
seek $_[0], $_[2], 0;
read $_[0], my $bytes, $_[1];
return unpack 'H*', $bytes;
}

Going with the assumption that each character was represented by 1-byte, the above code will return all chunks of six bytes that meet the following conditions:
1) Bytes 1 and 6 are identical.
2) Bytes 4 and 5 are identical.
3) Bytes 2 and 3 are unique.
4) None of the matches are on the blacklist.
After sifting through the output of my program, I finally stumbled upon the text string! Given how little text these VMU applications contain, I opted to just write the character message consecutively, tile after tile.

And alas, the final result (animated GIF)...

