2024-12-07

Sample Lufia 2 Fancy Character Movement Analysis

As I've noted previously, I've been working on decoding the scripting language Lufia 2 uses and trying to understand the less obvious details of what's going on behind the scenes in the various, well, scenes. (Lufia 1's scripting seems to be largely similar, incidentally, so feel free to use this as reference if looking into that.) Primarily, the point of this has been to extract the text cleanly and figure out what lines are used when, as well as what the progression of event flags looks like, but it's also been interesting to see how some of the more elaborate and expressive animations the game does so well work.

Let's take the scene in Tanbel when Maxim meets Guy and they decide to have a friendly duel as an example. It seems simple enough from the player's point of view. They face each other in an open plaza, Guy leaps at Maxim, and then they're interrupted before anything else happens. A surprising amount of effort goes into making the scene look good, though.

We'll start after everyone has moved into place and the initial banter has concluded.

Maxim and Guy face each other with an empty tile between them, while Tia watches from out of the way.

(Green text in blockquotes like the below is more or less what comes out of my script parsing program, minus the address offset data that isn't relevant here.)

{$34 1C 23: Change Actor $1C (Guy NPC)'s sprite to $23.}
{$37 0A: Brief delay, lasting 10 frames.}

Guy first switches to a different sprite to show him getting in a stance as preparation to make his leap.

Note that because he's not currently a party member, the Guy in this scene is a dedicated NPC.

{$4C 0C: Play sound effect #12}
{$34 1C 25: Change Actor $1C (Guy NPC)'s sprite to $25.}
{$34 00 1D: Change Actor $00 (Maxim)'s sprite to $1D.}
{$6C 1C FE FC: Draw Actor $1C (Guy NPC) at -2px X, -4px Y.}
{$30 5F 07: Put Actor $5F at map location #7.}
{$73 26 07: Play animation #38 at map location #7.}
{$37 01: Brief delay, lasting 1 frames.}

We hear Guy spring up, Maxim changes sprites to show that he's bracing himself, Guy changes into a leaping sprite and his displayed position is shifted two pixels to the left and four upward as his leap begins, and a dust cloud animation plays at Guy's starting location as Actor $5F is moved there. But what's Actor $5F?

Note that Guy has not logically moved at all; only the position where his sprite is drawn has changed. As far as the game is concerned, he's still actually on the ground where he started. If you could pause the scene and walk around, that's where you would find his collision and that's where you'd go to interact with him.

Of course, you can't pause the scene and walk around, so where he appears to be is all that really matters to the player at the moment.

{$6C 1C FC F8: Draw Actor $1C (Guy NPC) at -4px X, -8px Y.}
{$6C 5F FC 00: Draw Actor $5F at -4px X, 0px Y.}
{$37 02: Brief delay, lasting 2 frames.}

As Guy continues upward and leftward, Actor $5F follows him to the left, but stays at his initial height. It's his shadow!

Most sprites have shadows built in at the character's feet. Sprite $25 doesn't, so a separate shadow-only sprite is used in conjunction with it to give the impression that Guy is actually leaping upward and not merely circling around Maxim to the north side.

{$6C 1C FA F4: Draw Actor $1C (Guy NPC) at -6px X, -12px Y.}
{$6C 5F FA 00: Draw Actor $5F at -6px X, 0px Y.}
{$37 03: Brief delay, lasting 3 frames.}
{$6C 1C F7 F0: Draw Actor $1C (Guy NPC) at -9px X, -16px Y.}
{$6C 5F F7 00: Draw Actor $5F at -9px X, 0px Y.}
{$37 04: Brief delay, lasting 4 frames.}
{$6C 1C F4 EE: Draw Actor $1C (Guy NPC) at -12px X, -18px Y.}
{$6C 5F F4 00: Draw Actor $5F at -12px X, 0px Y.}
{$37 05: Brief delay, lasting 5 frames.}
{$6C 1C F0 EC: Draw Actor $1C (Guy NPC) at -16px X, -20px Y.}
{$6C 5F F0 00: Draw Actor $5F at -16px X, 0px Y.}
{$37 06: Brief delay, lasting 6 frames.}

The shadow continues leftward with Guy as he continues leftward and upward.

Notice that the delays are gradually increasing, while the vertical movements are gradually shortening, giving the impression of gravity affecting the jump.

Meanwhile, the horizonal increments increase at more or less the same rate as the delays, keeping the leftward speed more or less steady.

{$9E 14: Floating textbox; arg affects Y position:}
 Guy!!<$01=NEXT>

But now someone shouts, interrupting the action.

{$4C 14: Play sound effect #20.}
{$34 1C 23: Change Actor $1C (Guy NPC)'s sprite to $23.}
{$34 00 00: Change Actor $00 (Maxim)'s sprite to $00.}
{$6C 1C F0 EE: Draw Actor $1C (Guy NPC) at -16px X, -18px Y.}
{$37 04: Brief delay, lasting 4 frames.}

With the action interrupted, Maxim resets to his default sprite. Guy changes to a sprite with his arms in the air and starts falling with a corresponding sound effect.

Note that the detached shadow is still there on the ground below Guy, but the sprite he's switched to has its own built-in shadow, so he now has two shadows, one of which is hovering off the ground along with him. You should be able to spot this even at full speed if you're watching for it.

{$6C 1C F0 F0: Draw Actor $1C (Guy NPC) at -16px X, -16px Y.}
{$37 04: Brief delay, lasting 4 frames.}
{$6C 1C F0 F4: Draw Actor $1C (Guy NPC) at -16px X, -12px Y.}
{$37 04: Brief delay, lasting 4 frames.}
{$6C 1C F0 F8: Draw Actor $1C (Guy NPC) at -16px X, -8px Y.}
{$37 04: Brief delay, lasting 4 frames.}

Guy accelerates after beginning to fall, now topping out at 4 pixels per 4 frames, after starting with two steps of 2 pixels per 4 frames. His fall could be further smoothed out by using a series of 1-pixel shifts with 1-frame delays, but that seems like overkill. At full speed, it looks just fine as it is.

{$2E 5F: Deactivate Actor $5F.}
{$6C 1C F0 FC: Draw Actor $1C (Guy NPC) at -16px X, -4px Y.}
{$37 04: Brief delay, lasting 4 frames.}

Once Guy is a quarter of a tile from the ground, the detached shadow is removed by deactivating the associated actor.

{$6C 1C F0 00: Draw Actor $1C (Guy NPC) at -16px X, 0px Y.}
{$37 04: Brief delay, lasting 4 frames.}

And, at last, Guy has landed. The game is currently drawing him one full tile directly to the left of where it logically considers him to be.

{$34 1C 02: Change Actor $1C (Guy NPC)'s sprite to $02.}
{$30 1C 06: Put Actor $1C (Guy NPC) at map location #6.}
{$6C 1C 00 00: Draw Actor $1C (Guy NPC) 0 X and 0 Y pixels.}

Finally, Guy resets to his default sprite. The game also both moves his logical position onto the tile where he already appears to be and resets his rendering settings to draw him at his logical location, so although internally he's shifted one tile to the left, there's no visible movement.

All that just for Guy to leap at Maxim and fall to the ground! But the results are undeniable.

2024-12-01

The media has failed us

The local newspaper recently expressed some frustration with divisiveness and people talking past each other, and requested that readers write in, particularly regarding concrete reasons why they voted for one candidate or another. And I wouldn't normally bother, but something about the tone of it just got to me, particularly with how so much of mainstream media has, for years, consistently been bothsidesing everything and refusing to take a stand on anything, facts and consequences be damned.

I ended up toning down some of what I wanted to say and cutting out some relevant but perhaps overly verbose side rants, like noting how WaPo's billionaire owner decided to kiss up to fascism instead of allowing the actual writers to publish an endorsement of Kamala Harris, or how I wish she had been even half as much for they/them—which is a good thing to be!—as the opposing campaign claimed instead of remaining silent, or that most Democrats aren't even reliably progressive let alone leftist, or how the incoming Cabinet is composed of people who aside from general incompetence are openly hostile to the entire purpose of the departments they'll be in charge of, or...

...yeah, I think some editing was for the best. It's enough of a rant already without all that. Anyway, here's what I ended up sending them.


2024-11-09

It's already begun

The election is barely over, and the incoming administration is still months away from taking office, let alone taking any official action. And yet.

Already, corporations are raising prices in anticipation of the lean times to come (and with the assurance that there will be no meaningful effort to curb arbitrary price hikes).

Already, businesses are canceling bonuses so they can stockpile supplies before the promised tariffs hit.

Already, girls are facing taunts of "your body, my choice".

Already, Black students are receiving messages telling them they should report to plantations for cotton picking duty.

Already, calls to crisis hotlines have spiked to many times their usual volume.

Already, hate is emboldened.

Already, the world is a darker and more dangerous place.

And there's no reason to believe it won't get worse before it gets better. If it gets better. But we need to believe that it can get better, and strive to make it possible.

Perhaps a variation on the serenity prayer is in order.

Lord, grant me the power to endure what is beyond my ability to prevent, the courage to make a difference where I can, and the wisdom to know the difference.

Feel, grieve, commiserate. But stave off despair, and never give up.


(Yes, I threw in a Zelda reference. Things are so much simpler in video games. Where there is evil, you invariably have a clear means to fight it head-on. If you succeed, problem solved! If you fail, you can just load and try again. And if you still can't prevail, well, you can always put the game aside, no real harm done.)

2024-06-19

On Backlash Against Taking Title IX Seriously

In April 2024, the U.S. Department of Education released a finalized version of the regulations to be followed in ensuring Title IX non-discrimination protections in education, to go into effect at the beginning of August. Major provisions include clarifying that sex discrimination includes discrimination based on sex stereotypes, sex characteristics, pregnancy or related conditions, sexual orientation, and gender identity. And from the reactions in some quarters, you'd think the world was ending.

2023-12-18

Zombieconomy Sim Analysis

Introduction

Zombieconomy Sim, by Craze, appears in Befuddle Quest 4 Dead, the fourth in a series of collaborative puzzle games organized by kentona, which I recently (as of this writing) streamed a playthrough of on YouTube. It's largely similar to the Economy Sim minigame Craze contributed to Befuddle Quest 2: Charmed & Dangerous, but zombie themed.

And I found myself failing it repeatedly (refer to the end of Befuddle Quest 4 Dead (part 1 of 3)). So, as I tend to do, I went ahead and took a look at the design. After coming up with a plan, the next attempt went much more smoothly (refer to the beginning of Befuddle Quest 4 Dead (part 2 of 3)).

2023-10-08

PoGO Battle Requirement for Level 44 Clear!

So! News that probably no one cares about, but I've finally met Pokémon GO's challenge requirements for reaching level 44.

Background

Back when they increased the level cap over the original limit of 40, Niantic also added four special challenges per level that need to be completed before advancing, in addition to increasingly hefty experience requirements. Some of them have been pretty neat, like catching 200 in a single day or evolving Eevee into every possible form. And then there's the challenges for level 44.

2022-06-26

Woes for Modern Hypocrites

"Snakes! Cold-blooded sneaks! Do you think you can worm your way out of this? Never have to pay the piper? It’s on account of people like you that I send prophets and wise guides and scholars generation after generation—and generation after generation you treat them like dirt, greeting them with lynch mobs, hounding them with abuse."

- Matthew 23:33-34 (MSG)