I don't seem to be alone in this either, through my travels I've seen a number of people saying "haven't played in years, how's this thing work again?" in chat.
It's still mostly desolate, but there are definitely more players online now than there were a few years ago. Everyone's playing with hero parties from the looks of things, but... whatever.
That said, what the hell am I going to do in a number-of-years-old online RPG that I've already played to death?
Well, to start with, realize that there's still a lot I haven't done. What follows (after the break) is a list of tasks for my latest gaming project.
Wednesday, October 20, 2021
Finally.
Sorrow's Furnace was added to Guild Wars all the way back in 2005. I've had the quest To Sorrow's Furnace in my Ranger's quest log since it was added.
Today, I finally finished that quest. Now I can go on to The Final Assault and get him his Black Moa Chick. Oh yeah, I'm playing Guild Wars again. I actually started playing again back in 2020, just didn't post anything about it until now.
Edit (later this same day): Well, that was fast. Finished The Final Assault and got my Black Moa Chick.
Today, I finally finished that quest. Now I can go on to The Final Assault and get him his Black Moa Chick. Oh yeah, I'm playing Guild Wars again. I actually started playing again back in 2020, just didn't post anything about it until now.
Edit (later this same day): Well, that was fast. Finished The Final Assault and got my Black Moa Chick.
Sunday, July 4, 2021
JavaScript's Symbol.toPrimitive confuses me
JavaScript has all these built-in Symbols that can be used for various meta-programming tasks. Symbol.toPrimitive is a method on your object that gets called by the JavaScript engine when it needs to convert that object to a primitive value. It works by passing a string-valued hint to this function, this hint can be "number", "string", or "default".
Implementing it is quite easy. Just switch() on the hint and define your preferred logic for the three hints in their respective cases.
The confusing part is that JavaScript doesn't seem to have much in the way of logic behind what it chooses to pass for the hint. Initially, "number" and "string" seem obvious and the source of confusion is "what the hell do I do when it passes "default"?", but quickly the source of confusion becomes "I would have expected it to pass literally anything other than "default" in this case!".
To illustrate this, here's an example:
What makes absolutely zero sense, however, are the other two. When adding with a number, I would expect it to provide the hint "number", but instead we get "default". Adding with a string also produces the hint "default" when I would have expected "string".
So uh... what the fuck?
In case this is a browser thing, I'm using Pale Moon 28.17. I haven't updated to 29.* because it introduces breaking changes to my setup that I haven't resolved yet.
Implementing it is quite easy. Just switch() on the hint and define your preferred logic for the three hints in their respective cases.
The confusing part is that JavaScript doesn't seem to have much in the way of logic behind what it chooses to pass for the hint. Initially, "number" and "string" seem obvious and the source of confusion is "what the hell do I do when it passes "default"?", but quickly the source of confusion becomes "I would have expected it to pass literally anything other than "default" in this case!".
To illustrate this, here's an example:
class MyClass { [Symbol.toPrimitive]( hint ) { switch( hint ) { case "number": return 42; case "string": return "meaning of life"; case "default": return "the two best words in the English language"; } } } var a = new MyClass(); console.log( +a ); // Hint: number; logs 42 console.log( a + 27 ); // Hint: default; logs "the two best words in the English language27" console.log( a + "" ); // Hint: default; logs "the two best words in the English language" console.log( `${a}` ); // Hint: string; logs "meaning of life"Unary plus getting the hint "number" is all well and good. The template string converting a to a string and therefore getting the hint "string" is just fine and dandy. That's also the only case I know of where JavaScript provides the hint "string".
What makes absolutely zero sense, however, are the other two. When adding with a number, I would expect it to provide the hint "number", but instead we get "default". Adding with a string also produces the hint "default" when I would have expected "string".
So uh... what the fuck?
In case this is a browser thing, I'm using Pale Moon 28.17. I haven't updated to 29.* because it introduces breaking changes to my setup that I haven't resolved yet.
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:
Yeah, negative one. Interest fully attained, what other valid values are there? I explored the negative dimension and here are the results:
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:
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.
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: NextThis 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-padThe 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=-8After 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=140Yes, 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.
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.
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:
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)
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:
- An XInput controller, with a compatibility layer that translates the game's DirectInput calls into the equivalent XInput calls. Basically, the reverse of x360ce.
- 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.
- 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.
Tuesday, November 10, 2020
Abusing C-Style Comment Syntaxes For Fun (and Profit)
C originally only had multi-line comments, which work like this:
Feast your eyes upon this abomination:
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!
/* 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!
Subscribe to:
Comments (Atom)


