Thursday, December 17, 2020

SmileBASIC 3DS DIALOG Instruction: Undocumented DIALOG Types

I don't know if these are documented anywhere and I'm too lazy to do the most cursory of research, so here I am posting the results of my independent discovery.  Gather 'round, because it's time for everyone's favorite thing in the world: Storytime with XT!

I was poking around the Smile tool when I noticed that the graphics editor presents a strange-looking dialog when you press Y.  It lets you press A, X, or Y to achieve various goals, or B to return to what you were doing without modifying anything.  This dialog is presented in the same graphical style as those produced by the DIALOG instruction, but it doesn't have the buttons at the bottom of the touchscreen that are normally there.  The built-in documentation for the DIALOG instruction only covers six types:
0: OK (default) 1: No/Yes 2: Back/Next 3: Cancel/Confirm 4: Cancel/Execute 5: Next
This piqued my interest, so I looked into the code.  If you also wish to do so, a simple LOAD "PRG0:SYS/SBGED" from direct mode will load the code into slot 0.  I searched through for a DIALOG instruction and came across a procedure definition on line 1228 called DLG that uses it and parameterizes the text (to a label representing DATA instructions to read), type, and caption for calling code.  Searching for code that calls it, I found that the line of code on line 1141 produces this strange dialog by calling DLG() with the type -1.

Yeah, negative one.  Interest fully attained, what other valid values are there?  I explored the negative dimension and here are the results:
-1: A/B/X/Y (A: 128, B: 129, X: 130, Y: 131) -2: D-pad (Up: 132, Down: 133, Left: 134, Right: 135) -3: A/B/X/Y and D-pad -4: L/R (L: 136, R: 137) -5: L/R and A/B/X/Y -6: L/R and D-pad -7: L/R, A/B/X/Y, and D-Pad -8: Touchscreen (Tap: 140) -9: Touchscreen and A/B/X/Y -10: Touchscreen and D-pad -11: Touchscreen, A/B/X/Y, and D-pad -12: Touchscreen and L/R -13: Touchscreen, L/R, and A/B/X/Y -14: Touchscreen, L/R, and D-pad -15: Touchscreen, L/R, A/B/X/Y, and D-pad
The numbers in parentheses are the return values from the DIALOG instruction.  These don't make it into RESULT, you have to assign it to a variable.  If it looks confusing to you, I can explain it.

Ignore all of them except for -1, -2, -4, and -8.  Notice how they only enable one distinct set of inputs to dismiss the dialog?  This is a bit field.  You can compute any of the other values by adding some or all of these four together.  Should you want to do this more easily, you can just stick this in your program:
VAR ABXY=-1 VAR DPAD=-2 VAR LR=-4 VAR TOUCHSCREEN=-8
After that, you can just add together your desired combination using the variable names and it will be self-documenting.  You may also find it cromulent to have similar variable names for the return values:
VAR DLGA=128 VAR DLGB=129 VAR DLGX=130 VAR DLGY=131 VAR DLGUP=132 VAR DLGDOWN=133 VAR DLGLEFT=134 VAR DLGRIGHT=135 VAR DLGL=136 VAR DLGR=137 VAR DLGTOUCH=140
Yes, I am beginning to hate the 3DS version of SmileBASIC for lacking user-defined constants.  All the more reason I should get SmileBASIC 4 on my Switch, I guess.

I have observed that ZL and ZR are nowhere to be found, and the return values 138 and 139 are also missing.  I tested all fifteen DIALOG types with XON EXPAD enabled on my New 3DS XL, and ZL and ZR did nothing with any of them.

I tested a handful of other values for the type parameter but came up empty.  Any value I tried that was less than -15 or greater than 5 produced an out of range error.

For the sake of completeness: If you want to inspect RESULT after showing a dialog using one of these types, it works as you'd expect for the DIALOG instruction, except that RESULT will never be -1.  Confirmation and timeout are the only values RESULT will indicate.

I hope that anyone still using SmileBASIC on the 3DS finds this useful.  I'm not sure how applicable this is to SmileBASIC 4, or the Japan-exclusive SmileBASIC BIG on the Wii U.  If this behavior was already documented elsewhere, now it's documented here as well.

Monday, November 16, 2020

Syrup and the Ultimate Sweet: Illustration 27

If you type the game's name into Google, one of the search suggestions is the title of this post.  I myself had gotten all the endings and was only missing this one illustration, and finding absolutely nothing to go off of on the internet, I set off on my journey to find it.  As a result, I don't know exactly what triggered it, but I do have it now, and I have a pretty good idea of what might need to be done to get it.

Oh and fair warning: I'm going to talk about the end of the story in this post, so if you haven't already played the game and seen all the endings, maybe don't read further.  Your call though.

I started by noting that the illustrations in the gallery are in the order in which they appear in the story.  Illustration 26 is the one where Syrup goes to sleep after seeing what was recorded on the crystal ball, and illustration 28 is from when she goes to return the crystal ball and has a chat with Toffee before going to sleep.  I figured it had to be somewhere around that specific point in the story.

My first step was going for Gumdrop End and experimenting with different choices on Mt. Sorbet, but that got me nowhere.  My next idea was to get Pastille to show up on Mt. Sorbet.  It had been a few days and I kinda forgot what I needed to do for that.  As a result I got Frozen End a few times.  The gist of getting Pastille End is: be nice to Gumdrop and tell Pastille you wanted to help him (when given the choice to supervise Gumdrop, help Pastille, or leave), then let Gumdrop disappear but help Pastille find her.  I forget if choices matter on Mt. Sorbet before telling Butterscotch you hate her in order to stay trapped in the cave.  If you end up in Treat's cabin, you're on the right track, just avoid getting the Worst End and you'll be good.  Once you're down off the mountain and have the crystal ball, look at it before going to sleep.

Anyway, I got Pastille End.  Then I remembered that Toffee End has a slight difference if you get it again, so I went and got Pastille End again, but this time Syrup had some new dialogue after seeing the scene in the crystal ball.  After this, I got the elusive illustration 27.

This was technically my third time getting Pastille End, but it was also the second time in a row getting this ending.  My recommendation is simply to keep getting Pastille End, and eventually you should get the illustration.  If you need to, play around with choices that you feel are less integral to getting Pastille End.

Wednesday, November 11, 2020

Sentimental Shooting: Compatibility Update

I've been trying to resist the "storytime" intro I often do in my blog posts for this specific series, but this one does have a small story for context.

I was perusing some old speedruns on YouTube when I noticed one in particular was using a program called D3DWindower to force the game to run windowed.  I had been searching for something exactly like this, but I guess I just hadn't typed the right things into Google.  However, searching for D3DWindower by name and sifting through the results revealed an even better option: DxWnd.

DxWnd is now my official recommendation for running Sentimental Shooting on modern versions of Windows.  It fixes 100% of the palette corruption issues and allows a number of other useful tweaks.  Most of them don't actually apply to Sentimental Shooting, but the few that do could be useful depending on your needs.

You can add Sentimental Shooting to DxWnd simply by dragging and dropping SGSTG.EXE onto its window.  In the Options menu, enable Expert Mode so that the Tools menu will appear.  Then, with Sentimental Shooting selected, go to Tools → Clear Compatibility flags to clear any Windows compatibility options you may have set after following my previous post.  After that, right click on the game's icon in DxWnd and select Modify.

Here are the base settings I will recommend.  If a listed item is a checkbox or radio option, it should be selected.  Anything that's omitted should be left default (or in some cases, changed to suit your tastes).  For reference, all of this has been tested on DxWnd v2_05_59, which is the latest version at the time of writing.
  • Main
    • Name: Sentimental Shooting
  • Main → Generic:
    • Do not notify on task switch
    • No banner
    • Run in Window
  • Main → Position:
    • Hide desktop background
    • Keep Aspect Ratio
    • (W)idth: 640
    • (H)eight: 480
    • Desktop
  • Video
    • Initial virtual color setting: 8 BPP
    • Z order: top
    • Window size & position: Anchored
  • DirectX → Emulation
    • Renderer: OpenGL
    • Full bilinear filter (only if you can't achieve an integer scale)
  • Compat. → Tweaks
    • Win7 color fix (may not be needed outside of Windows 7)
As I mentioned with the Full bilinear filter option, it's only necessary if you can't get an integer scale when the game goes fullscreen.  If you're unsure whether or not this is possible, divide your screen resolution's height by 480.  If you get a whole number, congratulations, you can get an integer scale and don't need the bilinear filter.  Otherwise, enable the bilinear filter to make the game's bitmap fonts look right, and to reduce shimmering in the scrolling backgrounds.  Both of those issues are caused by non-integer scaling, and while the bilinear filter means you won't get the chunky pixels you deserve, it's better than the alternative.

Once you have the game configured and working when launched from within DxWnd, you can right click on it and select Proxy → ddraw to be able to run the game without having to launch it from within DxWnd.  When you do this, it will place some extra files in the game directory and the settings will be applied automatically when you launch the game.

These options will force the game to run in a pillarboxed 4:3 aspect ratio, so the graphics will appear as intended.  If you're one of those people who hates "black bars", please seek help for your mental condition.

With this new recommendation, the only remaining compatibility issue is for those who want to use a controller instead of the keyboard controls.  There are three options here:
  1. An XInput controller, with a compatibility layer that translates the game's DirectInput calls into the equivalent XInput calls.  Basically, the reverse of x360ce.
  2. A controller like the Logitech F310 or F710 (F310 = wired, F710 = wireless), that has a switch to toggle the controller between XInput and DirectInput.  If you want to use a controller but lack a controller for your computer, this is probably the easiest option, and it has the side benefit of also working with modern games.
  3. An older DirectInput-only controller, or one of the myriad of USB adapters for controllers from older consoles.  As long as there's X and Y axes (not a POV hat) and at least three buttons, it'll work.
Looks like we can see the light at the end of the tunnel.  There aren't really any more objective "best" options left, it's just down to user preference at this point.

Tuesday, November 10, 2020

Abusing C-Style Comment Syntaxes For Fun (and Profit)

C originally only had multi-line comments, which work like this:
/* no comment */
All characters between the /* and the */, including newlines, will be ignored by the compiler, and you're free to document your code as you see fit.  People eventually got tired of typing */ and thus the syntax // for a single-line comment was born.  Interestingly, we can abuse a combination of both comment syntaxes to easily toggle between two alternate blocks of code with the addition or removal of a single character.

Feast your eyes upon this abomination:
/* code block 1 /*/ code block 2 //*/
In that example, code block 1 is commented and code block 2 will run.  However, add a single slash at the beginning:
//* code block 1 /*/ code block 2 //*/
Now code block 2 is commented, and code block 1 will run instead.

This works because when the beginning is /*, it begins a multi-line comment.  The /*/ ends the multi-line comment, and //*/ is a single-line comment.  When the beginning is //*, it's a single-line comment.  The /*/ begins a multi-line comment, and the //*/ ends the multi-line comment.

Have a nice day!

Friday, October 30, 2020

Sentimental Shooting Graphics Files: Code Update

So, the disassembly thing is basically not going to happen.  Or at least, not by me.  As it turns out, people want tons of money for this kind of software and the free alternatives that I'm willing to run on my computer are lacking in documentation and the features I need to get my foot in the door.  Some are written in Python, which is annoying to deal with because everyone has their own pet version of Python that they never upgrade from and require you to install for all their stuff to work.

However, I can make my existing code better, and figure out more of the files.

I've already made the code better, by translating it to C#.  It runs faster and is far simpler now.  The reason for the simplicity is because my original PowerShell scripts were designed to work with paths containing wildcards and the PowerShell pipeline, so there had to be a bit of overhead in there to transition from one file to the next cleanly.  Stuff that an end-user probably wouldn't think of, but would absolutely annoy them if I didn't do it.  Namely, closing file handles properly so files don't stay marked as "in use" and become unable to be moved, renamed, or deleted.

But also in my typical fashion there was code in the PowerShell script for the UME files, for a use case I didn't need: some of the UME files are sort of grafted at the hip to System.ume, and being that the script was designed to be able to process an arbitrary number of input files, I put in code that would try to use System.ume from different directories, but if it's still in the same directory it'll keep the current System.ume open, and just seek back to the beginning of it.  It's kinda dumb, but I wrote it off as being forward-thinking.  After all, this code I'm working on could very well be the basis for modding the game, so maybe you have files for a few different mods you want to convert and they all have their own custom System.ume...  While ostensibly there to avoid closing and reopening the same file repeatedly, it does have this other use case.

Yeah, like I said, it's a use case that I didn't actually need.  It's technically preserved in the C# code, but the C# code also only handles one file at a time.  If you want to process a whole directory, you get to call the method once per file, specifying the path to your desired System.ume with each call.  Yeah, there's some overhead to that, constantly closing and re-opening the same System.ume, but the code's cleaner and easier to follow.  I also got to re-examine what I was doing and remove some of the stupider bits, so the new code is just... more better.

Both the PCG code and the UME code now exist as C# static methods, along with a couple static methods I created to see what was going on with my transformation of the input path to the output path, that I decided to leave in there because why not.  They could be useful.  Yeah, the methods don't take an output path as a parameter, they just transform the input path and then bitch if that file already exists.  That's kinda how I roll I guess.  I did put in a lot of work transforming the file names to be useful, it's not just extension swapping.  For example, Akr1b.ume will get transformed to Akira Stage 1 Background.bmp.

As for figuring out more of the files, honestly, without the ability to understand what's going on in the game's code, I can't do very much more.  The interesting stuff, the PRT, ROT, SPR, and DMO files, will all take more work than I can realistically do right now.  Running some quick commands to get file extension stats shows there's a couple other oddballs in there as well, Enemy.inf and Enemy.pnt.  I've looked at those and have no clue where to start.  This leaves two pieces of extremely low-hanging fruit: Option.dat and Destroy.scoOption.dat holds the options, of which the game only has a handful, and aside from the difficulty setting they're all toggles.  Destroy.sco holds your high scores.  They're such low-hanging that I already have classes for both to allow creating, loading, and saving them.

Destroy.sco was interesting because it contains the same structure repeated 12 times.  I chose to represent this in two ways: named properties on my class to allow accessing a specific stage's data by character name, and a custom indexer that puts the stages in the order they appear on the stage select screen from right to left.  That's actually significant because the score data in Destroy.sco is not in the same order as the stage select screen.  Figuring out the order was easy enough since it was simple to identify which values in the file were the scores.  I just set each stage's score to a number from 1 to 12, so when I looked at it in-game I could see which score showed up where.  Because I implemented an indexer, it didn't feel right without a Count property and an IEnumerable<T> implementation, so those are present as well.  I didn't implement ICollection<T> because it's not actually a collection and doesn't need management methods.

Also, the scores are signed values, which is interesting because if you give it a negative score, it reads an incorrect graphics tile from System.ume when it tries to display the minus sign, despite the fact that there is a minus sign available.  Also, if it has to display more than 7 characters for the score (7 digits, or 6 and a minus sign), it won't fit properly in the box on the stage select screen.  My code range checks and sanitizes both the scores and the percentages to avoid causing display bugs.

The structure of Option.dat suggests to me that the difficulty setting was probably added later on in development.  It appears at the very end of the file even though it shows up at the top of the options screen (everything else is in the order in which it appears on the options screen), Normal difficulty has a value of 0, Easy has a value of 1, and Hard has a value of 2.

Anyway, I've basically done all I can do in terms of figuring out file formats.  I suppose that my next endeavor will be trying to tweak the game's graphics files to avoid the palette corruption.  This will be annoying given that I can't get GIMP to load the palette from the files in its palette editor.  Worst case scenario, I have to roll my own code to change a palette entry and update palette indices to point to the new color, because I'm not writing an image editor.

Friday, October 2, 2020

Sentimental Shooting Graphics Files

So at the end of my previous post, I left a juicy little nugget of information about me poking around the game's graphics files.  I've "completed" a major milestone in doing so, and while there's still stuff left to do, I have enough to actually post about.

The game's graphics are in the PCG and UME files.  Judging by file extension alone, you wouldn't expect them to be any kind of standard file format that's documented outside of a dark corner of the internet, but... you'd be wrong.  Both are standard Windows BMP files, changed ever so slightly so that they don't appear to be proper files if you change their extensions and open them.

The PCG files are the omake pictures, and simply have 0x70 added to the first 0x03E8 bytes of the file.  That's it.

The UME files are the stage backgrounds, clothing fragments, enemy and boss sprites, menus, and everything else.  System.ume is actually a BMP that's just renamed, but the rest are very close to being proper BMP files.  Some have extra bytes at the end that any viewer or editor can easily ignore, but the real kicker is that they have improper data for some of the header fields.  You can make extremely minimal changes to allow an image editor to open them, but... for the stage backgrounds at least, we have the ability to make the game output the file directly.  Making these minimal changes does not result in a file that matches the one generated by the game.

Thus began my journey for matching output.  I discovered that the stage backgrounds saved by the game in the SNAPSHOT directory have various values pulled in from System.ume, including the color palette.  Most of the UME files for stage backgrounds actually have a zeroed out section of their palette where the palette from System.ume should go, which made it easy to spot.  Something about how the game handles the data zeroes out the padding in each row by the time it ends up in the SNAPSHOT directory, and any extra bytes at the end of the file get removed.  Towards the end I identified two groups of files that needed different behavior, but couldn't pinpoint how to detect this from the file contents alone, so I gave in and implemented dirty hacks that check hardcoded filename lists.  It's finally over, I have matching output for all 24 stage backgrounds, and no visible corruption in any of the other files, but... it doesn't feel right with the dirty hacks still in there.  This is why I put the word "complete" in quotes in the first paragraph: It works, but I don't like it.

One issue is that some files exhibit... interesting changes if the System.ume palette is imported, even though they have the space for it.  Some of these changes are easily identified to be incorrect, but others I'm not so sure.  I have an idea how to proceed here, but it's low priority in the long run.

A major sticking point is that I have no idea if my code that generates matching output for the stage backgrounds also does so for any of the other files.  I have no way to make the game output these files, and thus no way to see what needs to be done.  Or, do I?

I have reached a point where all of my remaining logical steps involve disassembling the game to see how it loads the UME files, handles the color palettes, and outputs snapshots.  This will be difficult for me for three reasons:
  1. I don't know x86 assembly
  2. x86 assembly is far more complex than the assembly languages I've learned so far (Z80 and 65816)
  3. I don't trust the NSA so I'm not installing Ghidra (so there goes its much-touted decompilation feature)
I can still think logically enough to know how to proceed after getting a non-Ghidra disassembler installed, though.  I've already looked at SGSTG.EXE in HxD, and I can clearly see the strings the game uses.  Windows executables include the names of the various API functions called by the executable, and I can see the various file names as well; so labelling all the strings I'm interested in and then searching the code for references to them seems like a cromulent first step.  From looking around at different disassemblers, "identification of Windows API calls" is a feature that pops up a lot, which would be handy.  Figuring out how it builds the palette from reading the files shouldn't be that difficult once I have my foot in the door, it's just a matter of copying data around and that's generally pretty easy to follow in any assembly language.

Still though, I now have PowerShell scripts that work for both the PCG and UME files, both of which produce output that matches what the game outputs on its own for every file I can possibly verify it with.

Fixing the palette corruption issues that the Windows compatibility modes mitigate by tweaking the corresponding UME files looks to be possible.  Logo.ume defines a full 256-color grayscale palette but only uses a small portion of it.  Enemy2.ume, which contains the sprites in which I'd noticed some palette corruption, has plenty of unused palette entries.  I just need to figure out which palette entries get corrupted, and move them to areas of the palette that were previously unused.  The disassembly can potentially help with that, if I can catch where the palette corruption happens and discover its true extent.

The pipe dream would be to fix whatever code is causing the corruption in the first place and just patch SGSTG.EXE.

I think I'll leave it there for now.  I'm at the point where I can open a BMP file in HxD and identify all the fields without having to consult an external reference.  If I don't post anything on this subject for a while, I've probably drowned myself in x86 assembly just to tweak a silly hentai game, or given up.

Monday, September 21, 2020

Sentimental Shooting Revisited

So a long time ago I posted about this game.  In case you're unfamiliar and too lazy to click the link, it's an ero-danmaku game released in the late 1990s.  I unironically enjoy it, not because of the nudity, but because of the gameplay.

In my post, I mentioned that having the music enabled causes the game to crash unless you're on Windows XP.  The reason for this is now very clear to me after having done some basic research: Microsoft has been gradually degrading the MIDI support in Windows, and XP was the last version to have proper support.

This means that you can, in fact, have the music enabled without the game crashing.  You just need to do some extra things first.

First up, if you're on Windows 8, 8.1, or 10, you'll need to install CoolSoft MIDIMapper.  Full disclosure: I'm using Windows 7, so I'm unfamiliar with actually using this.

Next, on Windows Vista or newer, you'll need to install CoolSoft VirtualMIDISynth.

Now, in VirtualMIDISynth, there's some configuration that needs to be done.
  1. On the MIDI Mapper tab, set VirtualMIDISynth as the default MIDI out device.
  2. On the Soundfonts tab, you'll need to click the plus button and select a soundfont.  You'll need to download one of these, and thankfully, the download page for VirtualMIDISynth has links to a good number of them.  I downloaded the uncompressed version of FluidR3_GM, which so happens to be the first one in the list.
  3. Do the requisite clicking of Apply and/or OK.
That's basically it.  Now you can start Sentimental Shooting and enable the music.  The crashing should be completely gone.  If it doesn't work and you're on Windows 8, 8.1, or 10, try changing the default MIDI out device within MIDIMapper instead of in VirtualMIDISynth.  Unfortunately, I don't have a computer running one of these versions of Windows to test on.

However, enable the music cautiously, as the default volume was extremely loud for me.  I had to crank it down to around 30% for it to not be louder than the game's sound effects.  You can get back into VirtualMIDISynth's configuration using the system tray icon.  From there, double-click on the soundfont you installed and the volume setting will be on the dialog box that appears.

Additionally, there's something I did that you may want to do.  VirtualMIDISynth has two global keyboard shortcuts enabled by default, and I was worried about them clashing with other games.  On the Shortcuts tab, just click in each key combination's text box and press Spacebar, that seems to have disabled them for me.

Edit (2020-11-11): There's now a better solution for fixing the color palette corruption.  You should follow that post instead and ignore the suggested compatibility settings here.

There's still one remaining issue with the game, and to address that I need to contradict my earlier post.  Specifically, the part where I said:
That's it, no compatibility modes, no running as administrator, and no extra settings.
Without any compatibility options set on the game's executable (SGSTG.EXE), some of the game's graphics palettes are corrupted.  The only combination of them that seemed to fix the corruption for me was the following:
  • Run in 256 colors
  • Run in 640x480 screen resolution
  • Disable desktop composition
  • Disable display scaling on high DPI settings
The last two make sense, sort of, but the first two seem redundant to me: the game already runs in 640x480 with 256 colors.  Nevertheless, the palette corruption wasn't fixed for me without both of them checked.  There are still two scenarios where the palette corruption will happen, and your only recourse to fix it is to restart the game: If you sit at the title screen long enough that one of the demos starts playing, or if you Alt + Tab out of the game and return to it later.

If you're unsure what the palette corruption looks like, well, the logo when you first start up the game isn't supposed to be red, or color-fringed.  Also there's an enemy that sometimes appears outlined in white instead of black.  Those are the only two instances of palette corruption I've noticed, at the very least.

I've been tinkering with the game's graphics files and may be able to provide patched files that don't experience the corruption, we'll have to see.  More on this as events warrant.