Logo Pending


Exodus

Not Ultima or even God forbid the Bible. I mean of course the one following the Tumblr porn ban. I’ve mentioned it on Discord once or twice but when you’re using a service like Tumblr to host and serve your content, a service provided by a company you can’t meaningfully control, you run the risk. The service will eventually cease to be (GeoCities says hello), the company decides to make one too many dumb functionality changes, or as happened now the advertisers force the company’s hand and they do the most fucktarded thing imaginable, in the worst way.

But to say you’ll just jump ship from the one company’s service to another? That’s just sitting and waiting for the other service to take a turn fucking up.

That’s why you sigh, fork over a tenner a month, if even that much, and get your own damn server. Do what you want, host your own blog and all its content. Use the services, untrustworthy as they are, to announce the content.

[ ] Leave a Comment

On fonts

SCI, being rooted in MS-DOS and from a time before Unicode (fun fact, the first draft proposal dates back to 1988, when King’s Quest 4 came out as the first SCI game), SCI uses an 8-bit string format. That is, each character in a string is one byte, and that’s all it can be. Making strings one of very few standard data types in SCI that aren’t 16-bits and requiring a dedicated kernel call to manipulate (as seen in KQ4 Copy Protection) but that’s not the point here.

American releases of SCI games would normally have font resources ranging only up to 128 characters, with the Sierra logo at 0x01 and ~ at 0x7E. Only caring about newlines, all other characters are considered printable. European releases would include usually not 256 but 226 characters, up to ß at 0xE1, basically copying code page 437 but leaving out the graphical elements among others. This means, of course, that a Russian translation of such a game would require another custom font copying code page 866 instead.

And then there’s the whole thing where SCI Companion uses the Win-1252 code page (it’s not exactly a Unicode application) which makes translated games look pretty wild:

Ich glaube Dir gern, daá Du das tun m”chtest!

That doesn’t look quite right. That’s supposed to be “Ich glaube Dir gern, daß Du das tun möchtest!” And indeed, comparing things between DOS-437 and Win-1252, we see that á and ß are both encoded in the same byte value.

That’s the kind of bullshit Unicode was made for, isn’t it?

So what I did for my SCI11+ project, of which one version is used in The Dating Pool, is to add optional basic Unicode support, so you can write text data in UTF-8 and not have to worry about things all that much. There are however two major problems with this idea. One of them is that SCI Companion is not a Unicode-aware program, so you can’t use that to write the text data. That’s easily solved with external resource editors that are. The second is more insidious — the fonts.

What I found out about SCI font resources is this: their header fields are way too wide.

typedef struct
{
  word lowChar;
  word highChar;
  word pointSize;
  word charRecs[0];
} Font;

lowChar is always zero, but the interpreter does acknowledge it. highChar is, as discussed above, always 128, 226, or 256. The fact that it’s exclusive is basically the only reason to have it not be a char-type value.

.if bx < es:[si].highChar && bx >= es:[si].lowChar

See? Exclusive. But the takeaway here is obvious. SCI font files can contain up to 65,535 characters. That’s enough to cover the Basic Multilingual Plane. As such, I’ve added handling of double- and triple-byte UTF-8 sequences to SCI11+. I’ve tested it, too:

Switching to another, non-extended font, I expected to see "Tend ", and that’s exactly what I got. The routine I linked to would decode an ō and dutifully pass it on down to StdChar, which would see that 0x14D is way higher than 226 and simply draw a blank.

(Now, between the first draft of this post and its publication, I’ve further enhanced this system to not decode anything if the font has fewer than 256 characters, falling back to code page 437 or whatever, just not doing anything special.)

That leaves one last issue, which is mostly a matter of wasted space. I like my quotation marks to be proper curly, and in Win-1252 as The Dating Pool uses (because why shouldn’t it?) this is easy — just draw a  and in the font at 0x93 and 0x94,  and be done with it. But in Unicode, these two characters are part of the General Punctuation block, which starts all the way at U+2000. That would mean defining up to that many dummy characters. A two-byte pointer, two size bytes, and a single byte with at best one bit set per character.

That’s bullshit.

As such, I’d propose to cheat like hell and move the General Punctuation block so it covers the much earlier Combining Diacritical Marks block. It’d be way too much of a nightmare to support those. So while measuring and drawing, detect if you’re in the 0x2000 to 0x206F range, subtract 0x2000, add 0x300, and use that character instead. Or have the custom resource tools  that we’d need anyway do it.

(Again, just before publication, I came up with an idea to have a new font generation tool that takes a bitmap of the font and converts it. The trick for space-saving is that it would recognize graphics it’d already processed and simply place a pointer to the first one. Instead of five bytes per dummy, it’d use only two for all but the first. Savings!)

(Update: I made the thing.)

At any rate, your input is appreciated.

Except for yours, Covarr.

[ , ] Leave a Comment

Musings on iMuse

One of the things I think LucasArts got Sierra beat in with regards to their old point-and-click adventure games has to be the music. I don’t mean that the music itself is better, but the underlying technology.

In SCI, a given music track can have cue points and a loop. These cue points can increase or set a value visible to the game engine, and let the game time things accordingly. Notable examples off the top of my head include the singalong text and images in Freddy Pharkas Frontier Pharmacist, the selection highlight following the beat in Quest For Glory, the singalong in Leisure Suit Larry 6… yeah.

But that’s just one way. The song can nudge the game, and that’s about it. A harmless bit of Mickey Mousing at best.

iMuse, on the other hand? The DirectMusic of its day. Remember DirectMusic? Me neither. Anyway, an iMuse song (near as I understand it) has queued triggers and a sense of beat, allowing the game to say “hey, switch to the cartographer’s version of Woodtick” and the song would wait for the current beat to finish, play a little flourish, and seamlessly transition into a different song. You could cancel them too, if you were fast enough. And let’s not get into the most triumphant example I’ve heard so far, X-Wing/Tie Fighter.

I figure if you give an SCI track beat markers, preload a fill riff, and have a script listen for requests, you might be able to approximate the basics. If you’re playing variations of the same song that only differ in instruments, you might be able to mute specific tracks, or send raw “Program Change” messages if you’re really adventurous…

But yeah. That’s why you can have proper MIDI dumps of SCI games, but you can’t quite hack it with most SCUMM games.

[ , ] Leave a Comment

What’s even the deal with felinese?

I’m glad you didn’t ask. When I originally started my Felin mod for Starbound, there was no associated conlang. I had some signage that I’d written in the Standard Galactic Alphabet from Commander Keen, but that’s about it. I did early on have the idea to make the felin very sexually open, with sex workers you could visit (even if not buy services from) that would be heavily implied to be self-employed and happy with their job and all that.

They had this sign at the door:

If you can read SGA, you can figure out what this says. Or just hover over it like a caveman. The sex workers themselves, even though the term would never appear on-screen, were defined in the prostitute.npctype file. All was good for a few weeks or so.

And then I got a private message from one of the forum moderators:

Someone has just reported the mod, claiming that there is a “prostitution NPC” included as an “undocumented and unreported ‘feature'”. Now, I thought I’d bring this up with you before anything else. Is there any truth to this? Maybe the NPC in question exists, but is not a prostitute. Or the person reporting it is just plain wrong. In any case, I’d like to hear from you about this.

I will never forget that moment.

So what I ended up doing to appease the mod (who agreed that the person reporting it was wrong) was to rename the NPC to something less explicit. A comforter, perhaps? And that’s what almost immediately evolved into the Four Paths that the felin follow, making prostitutes a kind of comforter, along with doctors and bartenders. But that’s another dumb story.

That just left the sign. The most explicit, visible thing about the prostitutes. It wouldn’t be that difficult to find out what that second line involves. So what I decided I’d do was, I’d rewrite the sign. But there’s only so much space on it…

If “intercourse” won’t fit, and another language is too readable, why not use your own?

Even if you can read SGA, you’ll find there are characters on this sign that you can’t recognize. And yet, this says basically the same thing as the other sign, including the full word for “intercourse”, in a completely functional language with 2,379 words and counting.

Those two words were quite literally the first I’d defined.

[ , ] 1 Comment on What’s even the deal with felinese?

The State of Noxico

Okay so what has happened to Noxico this past year. Let’s see, can’t be a lot, right?

First of all, I moved the thing to Github. The Bitbucket repo is still there, but I can’t say for how long. Going by the commit history as seen on Github…

  1. Reworked a bunch of text things to use Lua in hopes of making i18n easier.
  2. Added color support to fonts.
  3. Fixed a dumb bug that removed water when restoring a game.
  4. Added general support for weighted lists.
  5. Used testing characters to reveal and fix a bunch of things.
  6. Added a Markov chain option to name generation. 
  7. Reworked clothes tearing to give clothing a torn token instead of replacing them with entirely different items.
  8. Made character stats defined in Lua.
  9. Completely reworked the walkaround UI. Again.
  10. Overhauled the mod system, because I like Starbound.
  11. Added a test arena option, because I guess I kinda like Dwarf Fortress?
  12. Finally started on the team behavior thing that I’d been sitting on all this time.

In roughly that chronological order. I’m not sure about some of the Lua things, because of the whole “start from index 1” bullshit, but eeeh. It certainly bit me when I tried to convert the team behavior lookups to Lua, and that makes me worry about the attack multipliers.

[ ] Leave a Comment

King’s Quest 4 Copy Protection

King’s Quest 4 – The Perils of Rosella starts with a copy protection challenge right off the bat.

If you were playing the original 1988 version you could just enter the magic word “bobalu” and be done with it, but the 1989 version removed this.

It’s a pretty simple challenge-reply system, but the interesting bit is how your answers are considered. If someone were to somehow find the challenges they would also find the answers in the same order, but there’s a catch: the answers are hashed.

Very simply so, but they are. And of course the script code containing the challenges and answer hashes is compressed in the RESOURCE.001 file, and the whole thing is script code and nobody outside of Sierra could be expected to be able to read that stuff back in 1988. Sure, maybe some people could but still good luck figuring out how this worked. Even the backdoor phrase was compressed.

But now it’s 2018, nearly 2019, and I for one have made happy use of the tools now available to us, mostly to slake my own thirst for knowledge. So here’s how it works.

The copy protection script has several local variables: a random number from 1 to 79, the challenge text, the correct answer’s hash, a buffer for the user’s input, the hash for said input, and some work variables.

On startup, the random number is chosen. Then, in a big ol’ switch statement, the correct hash is decided on:

(switch (= randomPick (Random 1 79))
  (1 (= requestSum 431))
  (2 (= requestSum 521))
  (3 (= requestSum 535))
  ;...
  (79 (= requestSum 686))
)

In another big ol’ switch (instead of doing it at once?), the matching challenge is set up:

(switch randomPick
  (1 (= requestText "On page 2, what is the fourth word of the first sentence?"))
  (2 (= requestText "On page 2, what is the fourth word of the second paragraph?"))
  (3 (= requestText "On page 3, what is the fourth word in the first paragraph?"))
  ;...
  (79 (= requestText "In the section TIPS FOR NEW ADVENTURE PLAYERS, what is the eighth word in the first paragraph of tip #2 (STAY OUT OF DANGER)?"))
)

Incidentally, I said our guess would be stored in a buffer variable, that is an array in memory large enough to contain it, but I did not say any such thing about the challenge text. That’s because it’s stored as a pointer to the text, in the place it was loaded to as part of the script. From then on these challenges don’t mutate in any way. Our input can be literally anything.

Anyway, after displaying the challenge, we have our input in a buffer. This is where the magic happens:

(= i 0)
(while (< i (StrLen @userInput))
  (= ch (& (= ch (StrAt @userInput i)) $005f))
  (StrAt @userInput i ch)
  (= inputSum (+ inputSum ch))
  (++ i)
)

Iterating through the user’s input, we read the next line inside-out. Using the StrAt function we fetch the next character and store its value in our work variable. Then we use some binary magic on that same value to turn it into UPPERCASE, and assign that to our work var. Now, as I write this I feel like this can be simplified a little bit…

(= ch (& (StrAt @userInput i) $005f))

…Yeah, that seems nice. I don’t think it’d hurt functionality to do this. Anyway, the next line shows how SCI function and kernel calls can be variadic as all get out — given three arguments, StrAt will set the character on the given spot. In the third line, we add the character’s value to our running sum.

And that’s it! We can now compare our input to the expected answer, and either continue on to the title screen or display an error and quit.

But that’s not all there is to it. First, for some reason, the input is uppercased and then stored again, character by character. This is so the 1988 release can compare it against the magic backdoor word, which is also in uppercase. This seems like an awful waste when you could compare it against a number instead. Not to mention, the 1989 release doesn’t even have the backdoor and still does all this. (For the record, that would be 437.)

Second, this is such a simple method that there are guaranteed to be words with the same hashes. For example, “voice” and “licks” are both 374.

But yeah, that’s just about all there is to know about the copy protection in King’s Quest 4 – The Perils of Rosella.

[ , , , ] 7 Comments on King’s Quest 4 Copy Protection