Hi no Tori Tool-Assisted Superplay
- Manipulates luck
- Aims for fastest time
- Takes damage to save time
- Genre: Platform
Recorded with FCEU 0.98.16
Completed in 14:17 (51404 frames)
Completed in 14:17 (51404 frames)
I don't recall any story behind the game, but the objective is clear: you need to run through platform-style game and collect 16 pieces of big picture - by 1 piece at the end of each stage. When all pieces are collected, something marvellous will definitely happen.
The game is not so straightforward as most platformers. You'll need to search for teleports (hidden all over the game) and find your route through all 16 stages.
There are 4 zones:
1st - 7 levels, 6 bosses
2nd - 5 levels, 2 bosses
3rd - 3 levels, 1 boss
4th - 1 level
Oh those prime numbers.
One interesting feature makes the game rather unique - in case you're unhappy with level design, you can (right during main gameplay) destroy some platforms/blocks/walls/objects as well as ganerate blocks/platforms where necessary. The game could be looking more like puzzle if level designers would only try.
- Frame Advance + 9528 rerecords (not that much because luck manipulation was achieved without trial&error)
- NES debugger (study RNG function and stuff)
- Memory Watch + calculator (for luck manipulation/direct programming)
- Hexeditor (most obvious example - Lv.15) + nesmock
- FCEU with dual-movie support (used only because of Lv.15 dual walkthrough)
- ModPlugTracker for sequencing hi-freqency marches
Comparing this heavy list with Morimoto's "slowdown+rerecords" you may come to thinking that 15 seconds isn't an improvement in the case. In fact, I agree.. Well, let's hope that some additional aestetic value will save the day.
No programm errors were found, but I use L+R frequently to shoot backwards without turning and losing speed.
Useful memory adresses:
|12||Global Timer of the game. It keeps increasing until 255, then it drops to zero and so on|
|3F||RNG_Substractor value. Every time when RNG routine is called, this value increases inself by current value of GlobalTimer|
|40||RNG_Result value. At the end of RNG routine this value decreases inself by Substractor|
|6F||Boss damage (0-10h). Every boss needs 16 hits to defeat it. The highest frequency of delivering damage is: 1 hit per 6 frames|
|402||Current speed (C0h < 0 > 40h signed). Character's horisontal speed can vary from -64 to +64. Every level scrolls left-to-right, so I tried to keep this value at 0x40 (+64) for every frame possible||.|
|414||`freeze enemies` timer|
|415||`flashing mode` timer (A0h-0)|
|416||`mirror mode` timer (A0h-0)|
|417||`invulnerability` timer (after taking damage)|
Because of dozens of teleports, the game can be completed via different routes. Although Morimoto used quickest route, I wouldn't like to play the game as developers were expecting. Here's the picture.
Morimoto's route: 1 - 2 - 3 - 4 - 5 - 6 - 7 - 1 - 9 - 10 - 11 - 12 - 13 - 9 - 15 - 16 - 14 - 15 - 8
I've decided to take different path:
- to show where you will appear after completing Volcanic level (Lv.8)
- to make smth even more different from currently published run
- to simulate Final Boss battle (failed)
1 - 9 - 10 - 11 - 12 - 13 - 9 - 15 - 16 - 14 - 15 - 8 - 1 - 2 - 3 - 4 - 5 - 6 - 7
There shouldn't be major time difference between my route and standard one. The only difference is that you can stop recording a little earlier before taking last piece at Volcano (if your speed is high enough to touch the piece after input stops).
About luck manipulation in the game
In most cases speedrunner tries to manipulate luck by choosing best variant of events that can be influenced by input. So actually "luck" depends on player's patience in rerecording.
But in case of this game there's no obvious difference regardless of any actions you perform right before necessary luck event. You may spend thousands of rerecords for nothing.
Instead, there's way to predict RAM behaviour and calculate needed strategy long before critical luck event. That's it, the game can be played on paper. The result is quite cool: at the beginning of every stage I know exactly what to do (and when) without rerecords.
Unfortunately, this method is game-specific (while rerecords+analysis provide universal way to manipulate luck) and in HinoTori it comes from simple RNG and strict usage of RNG calls.
Here's how randomness in the game works.
At most cases the game doesn't use RNG values to make decisions, most of events are predefined. RNG values can remain untouched during several levels! RNG can be used by some bosses (esp. by those `falling objects` rooms) and sometimes by rare item drops.
Falling rooms use RNG periodically to set X-coordinate of new falling object. Bosses use RNG to make decisions (jump/shoot/run) or set current angle of shooting. Item drops may use RNG to choose "random item". That's all, nothing else can modify my precious RNG values. Therefore speedrunner can manage those values precisely - everything you need is to know how RNG works.
Here's piece of disassembled code:
C97A: LDA $12 ' take GlobalTimer C97C: ADC $3F ' add it to RNG_Substractor C97E: STA $3F ' save sum to RNG_Substractor C980: LDA $0406 ' take Player_X C983: ROR ' whether it is odd or even? ' result is saved in Carry_Flag C984: LDA $40 ' take RNG_Result C986: SBC $3F ' substract RNG_Substractor from RNG_Result, ' taking into account Carry_Flag C988: STA $40 ' save result of substraction to RNG_Result C98A: RTS ' return from subroutine, with random value ' in A register
If you don't get it, here's Visual Basic translation.
temp_a = GlobalTimer temp_a = temp_a + RNG_Substractor RNG_Substractor = temp_a ' therefore RNG_Substractor = ' RNG_Substractor + GlobalTimer temp_a = Player_X Carry_Flag = temp_a MOD 2 ' even/odd = remainder after division by 2 temp_a = RNG_Result temp_a = temp_a - (RNG_Substractor + (1 - Carry_Flag)) ' that is how SBC ' instruction of ' NES processor ' actually works RNG_Result = temp_a ' therefore RNG_Result = RNG_Result - ' (RNG_Substractor + (1 - Carry_Flag)) RETURN (temp_a)
Judging by this listing, there can be two ways to influence RNG usage. First way is to increase GlobalTimer (by pausing the game for necessary amount of frames) before game event calls RNG. Second way is to call RNG routine manually. If you need to prepare useful "randomness", you can calculate how much times you need to call RNG (but taking into account bosses' own calls, this is tricky).
RNG can be manually called by shooting an enemy at right frame. Usually when some enemy disappears (after being shot) it leaves "Block" item - you need to collect those and waste them to build walls and platforms. Pretty simple. But KONAMI added really ingenious feature - IF at the moment of enemy disappearing GlobalTimer reaches zero, it's up to RNG to decide whether to drop usual Block or some other item (almost any item!)
While playing Hi No Tori on my NES back in early 90s I figured that if you're lucky enough, sometimes you can receive unexpected item from any enemy (even from skeleton boss from Lv.15).
Here's listing of the game code for item drop routine. This piece of code is executed at the moment you hit an enemy with throwing chisel.
B917: LDA $12 ' watch GlobalTimer B919: AND #$7F ' but dont take into account 8th bit of GlobalTimer value B91B: BNE $B939 ' if GlobalTimer is not zero then drop normal Block B91D: JSR $C97A ' else call RNG subroutine B920: AND #$1F ' and truncate RNG value to needed form B922: CMP #$15 ' if this value is still < 15h then drop normal Block B924: BCC $B939 B926: CMP #$1E ' or if this value is > 1Eh B928: BCS $B939 ' then drop normal Block B92A: STA $061B,X ' between 15h and 1Eh... this branch of code drops ' item with ID = value from RNG B92D: LDA #$02 B92F: STA $0668,X ' ... technical stuff ... B932: LDA #$FF ' ... make all needed to convert enemy into item ... B934: STA $067E,X B937: BNE $B94B ' finally EXIT --------------------------- B939: LDA #$14 ' here is the branch of code which drops normal Block B93B: STA $061B,X B93E: LDA $067E,X ' ... technical stuff ... B941: EOR #$FF B943: STA $067E,X B946: LDA #$00 B948: STA $0668,X ' EXIT is here
EnemyHit_Routine: ' first we found out that current object was hit by player's weapon ' now we must decide whether to turn this enemy into Block or something temp_a = GlobalTimer temp_a = temp_a AND 01111111 ' clear 8th bit if temp_a <> 0 then goto Drop_Normal_Block temp_a = RND(255) ' Call RNG once temp_a = temp_a AND 00011111 ' crop generated value ' to the range of 00-1F if temp_a < 15 then goto Drop_Normal_Block if temp_a >= 1E then goto Drop_Normal_Block else ' DropRareItem Object_ID(current_object_number) = temp_a ' Turn enemy object into item object temp_a = 2 ' ... technical stuff begins ... ' each object has a number of properties like X/Y coordinates, speed and so on Object_some_property(current_object_number) = temp_a temp_a = FF Object_Direction(current_object_number) = temp_a ' direction property: 00 means `goes to the left`, FF - `to the right` goto EXIT Drop_Normal_Block: temp_a = 14 ' see Item Table - 14 means `Normal Block` Object_ID(current_object_number) = temp_a ' turn into Block temp_a = Object_Direction(current_object_number) ' take previous Direction of this enemy temp_a = temp_a XOR 11111111 ' reverse direction Object_Direction(current_object_number) = temp_a ' write property into object descriptor table temp_a = 0 Object_some_property(current_object_number) = temp_a ' write property into ' object descriptor table EXIT: 'EXIT is here
So in fact the game is violence-free. :) You don't kill anyone, you just turn enemies into objects of another nature. Here's the list.
|16||Beads (turn all enemies on screen into Blocks)|
|17||Rice Ball (restore energy)|
|18||Bag of money (500 points)|
|19||Whistle (freeze enemies)|
|1A||Torch (temporary invincibility)|
|1B||Mirror (walk through walls and enemies)|
|1C||SeaShell (power up for energy meter)|
|1D||Dark Block (+10 Blocks)|
Particularly important for speenrun is Mirror item. It allows you walk through walls, so you can easily pass through undestructable areas of muschievously designed level - without slowing down for a single frame.
The strategy is as follows:
- Prepare RNG_Substractor and RNG_Result values so that (RNG_Result - RNG_Substractor) = 1Ch
- Before you need to walk through wall, find a moment when GlobalTimer = 0 (or 80) and shoot some enemy
- Pick Mirror Item. Now you have 320 frames of unstoppable movement. If you're stuck in a wall, the `mirror mode` timer will freeze at 05, and the game tries to shift player object to the right (but much slower then in Megaman)
You can shoot moving Block item (which is item object) and it'll turn into an item (usually - another Block). Most of players think that they can change direction of moving Block by shooting at it, but actually they destroy one Block and therefore release another (moving to reverse direction). Don't need to say that if you shoot some moving Block while timer reaches zero, you'll turn the Block into something more useful.
Controlling the luck saved about 10 seconds in my run. Another 2 seconds were saved by better precision with bosses and level tactics. Plus 205 frames come from starting the game earlier.
Morimoto's run was very solid, and without this luck manipulation it couldn't be improved by more than several seconds. I wouldn't start this TAS without such interesting discovery, and I think the run deserves publishing not because of improving old Famtasia run, but because this
insignificant small game suddenly proved to be well-suited for TASing.
Level by level
The section contains kind of spoilers, so you'd better watch the movie before reading.
Quick and agressive start. If you didn't play the game before, here you can understand what the "Mirror" item can be used for.
Usually you are supposed to walkthrough this level and enter cave teleport only after second pass, but I'm way too impatient.
At first I've tried to manipulate Moai heads to drill best path for me, but then realised it's faster just to crack one block by triplejump. The experience of luck manipulation comes in handy later.
While it's absolutely unnoticeable, there are two critical moments of luck manipulation for level 12.
When the character walks on top of screen, he can shoot up with frequency of 1 shot per 2 frames. Hmm, this shouldd be abused...
Notice that some enemies can be manipulated by player's coordinates or by blocking their way.
First boss encounter! This Ridley-like alien never uses RNG, so I have nothing to worry about.
In the level I trade 5 frames (because of lag) to make three enemies move in certain way. Hehe, I'm fond of shoot-em-ups.
And now at the end of the level luck manipulation makes its first appearance.
Okay. Here's secret base of KONAMI. :) Here's where they create those addictive games and compose hell-catchy musics.
I couldn't resist to improvise some noise-channel marches with the character's weapon. Check them out.
Aww, now I see there's possible improvement - theoretically, by using mirror item you can take lower path (through walls) under broken bridge - therefore save 25 frames because of cracking teleport door faster.
But luck manipulation would cost 5-10 frames, and I've noticed this improvement too late to redo my further luck manipulations just for these 15 frames.
You'll remember this level. And the boss battle. Not because they are remarkable or anything, but because you'll see all this at least TWICE!
Technical note: in the level you gain speed twice slower and lose it (by releasing directional button) also twice slower. That's how ice surfaces work here.
Rather ordinary level. But I had to heavily hexedit it several times to prepare finest case for Lv.16 "luck loop".
Great. You are to play the same level up to the end and kill the same dino's skeleton.
I've intentionally made this level walkthrough similar to previous pass (in fact just copied buttons with hexeditor).
Of course I could play the level manually, but it would look even more boring then it looks now (hey, maybe not so boring after all). And it would be so LESS challenging (because actually there are differences in enemy spawns).
At other hand, hexediting finally has a chance to make its visual appearance - usually its work can't be figured by viewer. Here's my idea. Usually you can judge about used savestates by seeing extreme luck manipulation or risky movements. You can judge about used slowdown/frame advance by seeing perfect reaction and inhuman freaquency of button presses.
This level shows something that could be done only with The_Great_Hexeditor_Tool. No human can repeat his own actions so closely (even with savestates/slowdown/etc). And hey, that's what TA is about - show something that normal player cant show without tools.
Anyway, if you want to fast-forward this level, don't miss boss battle - at the end I have some free time, just enough to build my initial letter.
The walkthrough looks different from previous one, but you still may feel urgent need to fast-forward all the stuff up to the moment when I've used Mirror item second time.
Note: the character can't enter portal door while being in `mirror mode`. That's why I took Mirror much earlier (in the middle of level) and managed to save its effect to the end by frame-critical actions.
Generally, the level was designed to be the last. The main difficulty for non-TA player is shaking screen.
But for TAS player it's pretty boring, so just for fun I exploited luck manipulation to the extreme.
The evil scheme is following. Remember RNG code? Each time RNG just substracts RNG_Substractor from RNG_Result, and then RareItemDrop routine prunes this result to a value from 00h to 1Fh.
When we call RNG manually, RNG_Substractor doesn't change, because this time GlobalTimer = 0 or 80h.
Wouldn't it be great to have RNG_Substractor = 0 and RNG_Result = 1Ch (see Items Table)? This way we can have rain of Mirrors (or any other item - 1 RareItemDrop per 80h frames), because RNG_Result doesn't change after substraction.
What's more interesting, RNG_Substractor can be more then zero, doesn't matter until it is dividable by 20h. And RNG_Result can be 3Ch or 5Ch (20X + 1C).
So I rewrote couple of levels and created "luck loop". Wohoo!
Even though previous boss tried to spoil the fun with "luck loop", i still saved half of its characteristics. No matter how many times I abuse luck, RNG_Substrcator and RNG_Result remain ready for another Mirror drop.
Boss of this level can be thrown out of room, which is faster then making 16 shots (1 per 6 frames).
Luck loop continues. Boss room lags as hell, so I took a Torch Item and killed the most laggy enemy without releasing chisel weapon (additional object on screen would make lag even worse).
Very irritating level. I was upset by repetitive design, so the level is mostly walked by air - over all obstacles.
The boss makes 2 RNG calls which can be neutralized by choosing right frame of encounter. I still need my luck loop for Lv.5. So during the level I had to lose 6 frames, which is a reason to fool around a little bit.
The most boring level. An excuse to start and finish it with 0 blocks in stack. At the end you can hear famous "KONAMI pause" sound, which doesn't cost any frame. Hey, it's not like you can usually listen for it in speedruns.
At last this luck loop actually saves good amount of time. I wonder if developers realized the boss room can be acessed without knocking the door.
Unsteady bridge logs are objects as well as enemies and Blocks. Which means they can drop items too! While those logs don't have any collision box, we stiil can destroy them by taking Beads item (destroys every enemy on screen).
With correct timing there's a way to jump through the ceiling (what's more important - not a single frame were lost) and remember the ability to drum.
Platformer game should have final boss, and let it be this poor guy.
Enjoy simple and beautiful ending theme.
Level 9 - boss room. Maybe there's a way to change RNG_Substractor value so that Moai heads will destroy blocks for you. 10 frames.
Level 12. You can avoid 5-frame lag mentioned above by simply destroying ships and riuning the idea. 5 frames.
Level 9 - before teleport. It would be great to take Mirror and reach the teleport much earlier (running under bridge), but it's really hard to properly manipulate luck right after using Mirror at level 12. Up to 20 frames.
I didn't try to compare standard route (when Lv.8 = last) and my current one - but everything speaks that there's no significant defference. Only you can stop movie several frames earlier with standard route.
Note: I've tried to kill bosses instantly with Torch item (with this item you kill enemies by touching them), but bosses don't react on this.
Also, while entering any boss battle or piece room there's one unavoidable frame of lag.
That's all, I guess. Всем бабай! :)
Bisqwit: Accepting and processing. I like how you went beyond normal in TASing this game. I didn't expect the route to change, and your usage of the mirrors to speed up reaching the bosses was very clever.