Indivisible on NES (Playable ROM inside/Image Heavy)

Discussion in 'Indivisible' started by Kasumi, Dec 15, 2015.

  1. KaboomKid

    KaboomKid Sure would be nice. ...TUNA FISH!

    There ya go dude! Nicely done!
     
    Kasumi likes this.
  2. Kasumi

    Kasumi Better known as NEScoder

    It has been a while. This silly, little fan game came out a year ago. It wasn't my first release, but it's definitely the first that got any sort of real attention. To celebrate its anniversary, I'll share a story about massive panic I had before it came out.

    I launched it shortly after getting back from a road trip with a couple of friends of mine. The trip had a strange effect on my mindset about the whole thing. Maybe life in general. But the story's not about the trip, sorry!

    The fan game is based on what is now a very, very old Indivisible prototype. The last months of working on the fan game filled me with constant worry. I had a lot of small personal deadlines for the game and I missed them all. The very last one was "before the real game gets a playable update in a way that fully obsoletes the old prototype." For those not in the know, the actual Indivisible was a crowd funded game. The developers released the version the fan game is based on to show what the game might play like. If the game was successfully funded (it was), they had plans to release "demos" of new mechanics and things to those who backed at that level. These demos were to be called "Backer Previews".

    I wanted to release before the first Backer Preview.

    On June 20th 2017, the developers tweeted that the Backer Preview would be coming in a few weeks:

    My heart sank.
    I was working as hard as I could, but I was in a "race" with an actual team with actual experience working with modern tools on modern platforms with literally a million times more RAM and an actual budget.
    I was working entirely alone, on a budget of shoestrings and dreams, using bad tools I wrote myself for this fan game on a console that's older than I am.

    The Backer Preview had been delayed before, but I was honestly panicking. In August, the trip came up. It wasn't planned and actually went longer than I had guessed it might. I wasn't able to work on the game during it, I don't really have a mobile development setup. So during most of the trip it was in the back of my mind that the backer preview would come out while my version was idling at the finish line.

    "Why did you care so much about beating the Backer Preview to release?" I hear you asking. After spending a really long time cloning the old prototype, I didn't want more to do! And I wanted to avoid people wondering and asking why I didn't do all the new things that would be introduced.

    The devs tweet again in August when I am far away from home:
    It sounded very soon. After all, how much more time could I have when in June it was weeks away?

    I get home. I finish the game. I actually think the difference between the game before the trip and after the trip is just a few bytes. I changed some colors on the title screen. I primarily just wanted to test it on real hardware.

    I flew into action working on the promotional "trailer":

    I'm still pretty proud of it. While I'm sure actual video editors would scoff, it's the first real video editing I did. I threw it together in a very short amount of time without powerful software. (It couldn't scale up by nearest neighbor, so I had to manually scale the NES version's clips before importing them.)

    I do regret one thing. It doesn't say it's a fan project! On some level I think I only really expected people familiar with the actual game to play it, but there were a fair amount of people who played this who had (have?) no idea about its "modern" counterpart. I didn't really think about it, but there were definitely people that were fooled. Sorry! It also doesn't say anything about it being unofficial in the actual game... I did this because I want to match the original game. If that had credits, I'd have done that but it did not... Still, in the future if I ever do something similar again, I'll make it clear.

    I actually had a different plan for promotion but there just wasn't time. I wanted to make an animation of Ajna playing NES (hand drawn, not pixel art). I still wonder what it would have looked like. :D

    Having finished the promotional materials, a different worry started to sink in. How is this game gonna spread? I had like... 10? followers that were all people I knew because I signed up to twitter in preparation for launch. I didn't spend all the time just to have no one play it. So I started to test the waters on twitter. Most of my early tweets were made to test the kind of reach I had. The results were actually discouraging. Until this one:


    Aseprite retweeted that. At the time, it had around 10,000 followers. I actually instantly regretted tagging Aseprite in that test tweet. Why? What if they didn't retweet the actual release?! Did I waste my shot?!

    I finished testing the game. Everything's ready. And... I send it out. And wouldn't you know it, I pick a day and time when itch.io was having problems. The URL was 404ing for a bit. And I make a launch tweet to Aseprite. And Aseprite retweets it.

    Aseprite retweeted both my coming soon tweet and my launch tweet. Aseprite is actually a large part of the reason why people saw the game early on. Thanks Aseprite! Thanks. I actually wrote an Aseprite Love Letter earlier in the devlog. It's just that good.

    OH YEAH! Because of reasons, I just remembered missingno from here was also a large part of early exposure due to his reddit post! Hi! Thanks!

    A few days later, I hear from Mike Zaimont, the lead programmer of the actual game. And he ensures the game is retweeted on the official IndivisibleRPG account as well as sharing it himself. It was also retweeted by personasama and renderling (and maybe others on the team?! Sorry if I missed you.)

    Mike was super cool throughout the whole project. He was very patient with me. While he was busy working on the actual game, he still took time out of his day to answer some questions I asked just to help me make this fan game. Thanks Mike!

    Obviously, fan games run a risk of getting cease and desisted and I totally understand all the reasons for this. I don't take for granted how super cool Lab Zero was about this. They knew about the project for basically its entire development cycle and let it be.

    With the knowledge I have now, I probably would have made a few more changes before releasing it. There's a change I'd have made to the boss in particular, I was just too scared to change something so close to release.

    Well as it turns out, the Backer Preview came out in November. Thanks for reading!

    PS: There's still an unfound secret or two in this game! (Or, if it has been found, I've seen no public evidence of it.) I'd still like to write some posts about the development of this game, but apologies if the next one is a year from now!

    (I'll probably cross post this and future posts in tigsource or something. I like having all the posts in one place, but it might also be nice to have some stuff read by more than the extremely diehard Indivisible fans remaining on skullheart. But I also may just... never write more posts! We'll see.)
     
    Last edited: Sep 1, 2018
  3. MellowMarz

    MellowMarz New Member

    That was such a wholesome and nice story to hear. Especially the fact that the dev team really enjoyed your hard work and dedication on the fan game. It shows that the devs care a lot for their fans.

    I'm super glad you were successful on completing the fan game, and I'm interested on doodling the scrapped promotional idea with Ajna playing the NES.(seems cute)
     
    Kasumi likes this.
  4. Kasumi

    Kasumi Better known as NEScoder

    I'm glad you enjoyed the story. If you're feeling the AJNES concept, feel free to doodle it up! It's unlikely I will at this point.
     
  5. Kasumi

    Kasumi Better known as NEScoder

    I guess I should try finish this devlog/post-mortem up before the actual game comes out, huh? Strap in, this is a long one! It covers the design process and implementation of the very first complete boss I ever programmed, as well as things I learned from play testing, and bugs along the way.

    Boss Design and the Testing Experience

    This game is nearly two years old at this point, but I figure I should still warn: This post will spoil things. Feel free to try it before reading on: https://kasumi.itch.io/indivisible

    And since a few might read this who aren't familiar with the original game: Actual Indivisible is a game with metroidvania platforming, but when you touch an enemy, you can no longer jump or directly move the character left or right. Actual Indivisible's battle system is somewhere in between real time and turn based. The enemy can't act while you are doing something, you can only time blocking while the enemy is doing something. You can attack (or not) any time you have the resources to. It should be noted that all references to "Actual Indivisible", "The Real Game" and similar refer to the very old Indivisible Prototype from 2015, not the final release that was not available when the ROM (or this post) was made.

    NES Indivisible plays more like straight Castlevania. Touching an enemy just gets you hit rather than starting a new battle state. For the regular enemies, this ended up not mattering too much to me. You can kill most things reasonably quickly in Actual Indivisible, and all enemies have defined attacks and movement behavior when the game is in the "regular" platforming state.



    Adapting the bosses from Actual Indivisible presented an interesting challenge. The standard Actual Indivisible boss (called the Manote Thiha) never moves from where you find it. It doesn't walk, jump or run. When it attacks, Ajna (and party) can only block.

    The Manote Thiha pretends to be a statue. You run toward an opening. Pass it. It goes from monochrome to color and kicks you! It can be startling the first time!

    [​IMG]

    Even this felt a little bit wrong to replicate. In the real game, even if you know that's coming, it's actually not simple to avoid. NES Indivisible still has it unstatue and plays a sound effect that might startle you, but you're unlikely to get hit. After all, you only have 3 health! It's still possible to get hit, though! In a move that's a bit of the reverse of the actual game, you pretty much have to try to get hit (rather than trying to not get hit once you know the attack is coming).

    Rare footage of NES Ajna getting hit by the unstatue kick:
    [​IMG]
    You have to be dashing. The way the fall happens, people are unlikely to be.

    At this point in Actual Indivisible, Ajna would be unable to wall jump, jump, axe hang, or attack out of turn. NES Ajna is free to jump over the boss, and attack or switch "weapons" as she pleases. So naturally, the fight is entirely different.

    The Beginning...

    The first thing I did was draw and animate all frames for the entire thing! Sounds exciting, right? But I'm going to do animation in another post. (Hopefully in not-a-year ^_-) After that I started to get them into the game. It has been covered before, but most things people call a "sprite" on NES are actually made of multiple hardware sprites (which are only 8x8 pixels in Indivisible on NES).

    [​IMG]
    Each line on the right represents a different 8x8 sprite used to make up the whole Manote Thiha. (This program is NES Screen Tool )

    In game, it started like this:
    [​IMG]
    Something's up there, I just know it...

    That's actually the Manote Thiha displayed with Ajna's tiles.

    [​IMG]
    The same tile is highlighted in green on Ajna here. And here's the reverse:
    [​IMG]
    Ajna displayed with the Manote Thiha's tiles.

    Why the glitches? I animated all frames for all enemies before putting any in the game. (Or at least that's how I remember it!) This is bad practice (what if art changes are needed to serve gameplay?), but getting assets into the game was such a slog that I wanted to do all parts of it assembly line style.

    NES Indivisible has four "slots" for highly animated objects. At this point, the system to assign slots hadn't been finished (or at least wasn't working), so all things just used the tiles in the first slot.

    Fixed:
    [​IMG]
    This was actually before I implemented sprite "flickering". Contrary to a commonly hold misconception, more than eight sprites per scanline just makes the NES not draw the rest. The common "flickering" effect is done in software by each individual game, and makes it so different sprites get dropped each frame. At this stage, the same sprites are all getting dropped.

    Flipping through all the frames:
    [​IMG]
    I didn't point align them at first. (I can visualize Mike Z clutching his heart.) The last "frame" is just garbage data. Nothing stops the frame number from going out of bounds.

    You may be wondering why the Manote Thiha is green. Simple! There are four sprites palettes on NES. Ajna uses three of them. The fourth for most of the game contains green colors, used for the vines and the Ahp enemy. Since the Manote Thiha's area with its own palette wasn't placed yet, it uses the wrong palette.

    Here it is aligned and with the right colors (and still no sprite flicker!):
    [​IMG]
    NES can only display 64 sprites in one frame. The way the game was set up at this time, going over THAT would erase most of the sprites on the frame. The final version of the game has some behavior to "flicker" even for more than 64 sprites! No actual boss behavior has been implemented here. I can change frames with player 2's controller and that's it.

    I implemented sprite flicker to start with. After seeing how much of the visuals were getting dropped, it became a priority. It's not too hard, it's just assigning sprites starting at a different point in the set every frame.
    [​IMG]

    Because I had animated all frames for the boss before programming any of it, I thought I had a pretty good idea of what I wanted design-wise. The original Manote Thiha really only has three attacks (with variations). The first is the kick, which has already been shown.
    But hey, here's the regular variation rather than the "unstatue" version:
    [​IMG]
    The second is summoning fire:
    [​IMG]
    And the third is summoning enemies, which I don't have a GIF for. (But it's the same animation as summoning fire.)

    The flow of the fight in the original is pretty simple. You'll get kicked at, and you'll get flamed. When you've taken off about 1/4 of the Manote Thiha's health, it summons some enemies to fight with it. (Hungry Ghosts and Ahps.) When it's about 1/2 dead, it summons more powerful enemies to fight with it. (Belus.) Then you kill it, and you've beaten the game. (Maybe.)

    So my view was that the fight would be pretty similar. You'll get kicked at, you'll get flamed. The enemy summons will happen at around the same times. Rather than its summons fighting alongside it, which would have been very flickery and used more of those object slots than were available, the Manote Thiha would hide as a statue again as you fight its underlings.

    I started on the kick projectile behavior:
    [​IMG]
    You can reflect this! And reflecting it damages the boss more than anything else you can do! Most people don't realize it and it was harder in general than I expected it to be. One of the larger issues was actually animation. Normally it starts out big, gets smaller, then disappears. I don't remember the specifics, but initially reflecting it either restarted the animation (so if you hit it near the tail end it would immediately get huge again), or it stayed small. It dynamically grows in the final game. (If you hit it when it's small, it will grow larger before looping.)

    And I made the boss animate itself, instead of manually flipping through its frames:
    [​IMG]
    Made it respond to attacks... and walls:
    [​IMG]
    (Yes, the one player tennis was as fun as it looks!)

    When the boss dies, its own flames turn against it. Here was my first attempt at that:
    [​IMG]
    When a flame "dies", it creates another flame. I called the CreateObject subroutine, but didn't pass along what it should create, so it executed "random" stuff as code.
    Here it is correct:
    [​IMG]

    How most enemy characters were implemented was programming all the states they could have, then manually controlling them with player 2's controller to think about what the AI should do, and then making the AI do that instead of the controller. So of course I couldn't resist making God Mode:
    [​IMG]
    There were a lot of things that were super hard to not share absolutely everywhere while I was trying to keep a secret just how extensive the ROM was. This is one that almost broke me. The camera's a little glitchy since Ajna's positions work differently than the Manote Thiha's.

    When hit, the boss should not be launched or fly backwards like totally pathetic, smaller enemies, so I implemented an enemy property that I called "steadfast". Here it is tested on one of the more pathetic enemies:
    [​IMG]
    Basically when Ajna's attacks make contact with an enemy, they check the steadfast flag. If it's true, the attack will tell the enemy it got hit, but not modify the enemy's speed.


    At this point most of the things that the Manote Thiha was meant to do were implemented and rigged to player 2's controller. So I started to test fight the boss:
    [​IMG]
    This GIF actually took a long time to put together. I made it to share in semi-private places where I discussed the game. It's still me manually controlling the boss (and Ajna at the same time!), so it took a lot of takes to get just right. It really is just smoke and mirrors. The Manote Thiha can't even hurt Ajna yet:
    [​IMG]
    For a bit of nonsense:
    [​IMG] [​IMG]

    Finally the first part of actual AI. The Manote Thiha has been made to turn to face Ajna:
    [​IMG]

    I often say if you aren't at least occasionally playing your game frame by frame to look for errors, you are making a mistake:
    [​IMG] [​IMG]
    Indivisible objects can have a "steadfast" property. This means when they get hit, they remain still instead of getting knocked away. The Manote Thiha and Reflected Kick are both steadfast. The reflected kick looked for a steadfast object that was not itself to decide what to damage, under the assumption that the only other thing that could be steadfast is the Manote Thiha.

    So the reflected kick hits the new kick. A reflected kick can only hit once, so the reflected kick can no longer damage the Manote Thiha. The collision also tells the new kick it has been hit by setting some things in RAM, under the assumption it is the Manote Thiha. (That could have potentially been really bad, if the modified RAM were used differently for the Manote Thiha and the kick projectiles.) Because it has been told it was hit in a similar way to how Ajna's axe would tell it, it thinks it has been reflected, and so the new kick doesn't damage Ajna either.

    Why not just check for the Manote Thiha type in the first place? Due to how the game works, checking for a specific object type requires more compares than just checking a property. (Ajna has a property to identify herself to enemies to avoid those compares, but adding an additional way to identify all object types would have made each object use more RAM.)

    One more subtle glitch:
    [​IMG]
    The Manote Thiha is slowly inching forward while being hit. It's a problem of objects in hitstop not running all of the state logic in the frame. An offset is not being reset here.

    A lot of the setup was now done. It came down to specifically controlling how I wanted the fight to go:
    [​IMG]
    One of the things I noticed early on in the test fights was that Manote Thiha jumping backwards after being hit really, really sold it as being "alive". It jumps backwards to avoid more pain. The AI specifically does the same.

    I also realized another option if something just hit you is to hit back on reflex. So there's a chance the Manote Thiha will kick in reaction as a response to getting hit instead of jumping away. This (and trying to avoid "real" random number generation) caused a bug:
    [​IMG]
    I was using which frame for making "random" decisions. Since the hit response happens on the first frame possible, and since the kick always took the same number of frames, it kept doing it. I put in "real" (pseudo)random number generation...

    And now for what perhaps became THE design problem with this whole affair. Ajna can axe hang indefinitely:
    [​IMG]
    The kick will never hit. Which meant the fire "had to".

    So, simple, the fire is created directly on top of Ajna:
    [​IMG]
    If she's axe hanging high above the fight, she'll still get hit.
    Maybe a bit more often:
    [​IMG]
    Okay, not that often. I settled on 3. The initial plan was to start at 1, and make it become 3 once the boss was getting low on health. But this felt inconsistent. (The first time it does 3 after it has only previously done 1, you'd certainly get hit.)

    Ultimately, a lot of people had and have trouble with the fire, which is designed how it is to hit this axe hang.

    Let's talk about reaction time. There are about 60 frames in a second in Indivisible on NES. Suppose it takes a half second (30 frames) to recognize danger, and start to press the sequence of buttons to avoid that danger. This might make it seem like the fastest enemy attack can be 31 frames. But this isn't true because the player might be committed to something when the attack starts. Even if they recognize the danger, they can't get away due to that commitment.

    Upon pressing B while standing, Ajna was committed to a standing axe attack for 38 frames. (On frame 39, she could could act.) Suppose I press B. A frame after I do that, the Manota Thiha starts an attack that will hit me in 31 frames. Even if I had a 1 frame reaction time, I still couldn't get away because I was already committed to the axe before the Manote Thiha's attack even started.

    Now suppose I plan to hit the Manote Thiha. Before I do that, the Manote Thiha starts an attack that will hit me in 50 frames. 29 frames into the attack (before the hypothetical 30 frames I can recognize and input something to avoid the danger), I press B. On the next frame I realize the attack is happening, but it's too late. I get hit because I'll be committed to the axe for the next 38 frames. So the fastest an enemy attack should be is (human reaction time you're targeting)+(length of slowest commitment that's reasonable to do in the situation)+(however long it takes to actually avoid the danger). Why the third item? Suppose the Manote Thiha starts an attack that will hit me in 32 frames. I'm not committed to anything, so I recognize this on frame 30 and hold left to start moving away. On frame 31 I'm moving away, but if Ajna doesn't move far enough away in that single frame to not get hit, she still will.

    A note on reaction time while I'm writing about it. It is possible to beat a sequence without "reacting" to it. Here is a Battletoads GIF to demonstrate:
    [​IMG]
    If you are at the front of the screen (or near it), you do not have time to react to this particular pillar. (For people familiar with Battletoads, this is from the segment without the flashing warnings before the pillar scrolls in.)

    Frame 14113 is the first frame the pillar is visible in the GIF. Assuming a 1 frame reaction time to it, down can be pressed.
    On frame 14114, the down input is accepted. But it's not enough. Even with down held a frame after the pillar becomes visible, the crash happens on frame 14117.

    However, it's totally possible to beat this segment from the very front of the screen, because the way the pillars appear is always the same. You don't have to see the pillar appear to know which direction you need to press to dodge it if you already know the order. It's a bit like playing a musical piece from memory.

    If the pillars were random, that segment would not be possible to consistently beat from the front of the screen because you'd have to see the pillar before you could press the proper direction, and the pillars appear too fast for this to be possible. (Even if they were random, it'd still be possible to beat the segment, but it'd be due to guesses matching with the random number generator rather than reaction or memory.)

    The Manote Thiha has to be reacted to because it doesn't do the same things every time. The Manote Thiha's kick could hit 68 frames after its first visible startup frame, assuming you're as close as possible to it. This is too fast for the hypothetical 30 frame reaction time, but the average reaction time is faster. Its first flame can hit 79 frames after its first visible startup frame.

    The second flame and third flame can hit you 16 frames after their first visible frame. This isn't reactable timing in isolation, but since these flames behave consistently X frames from the first this is more or less fine once the player sees it once. (They will probably get hit the first time, though...)

    This GIF is not from an early build, but it contains the main ways to get away from the fire:
    [​IMG]
    Most people discovered the jump version that has a boomerang sort of flow. The left, right, left one is kind of like a rhythm game. Imagining that you need to "play the note" of each fire sound effect might help. While writing the post, I found this novel way:
    [​IMG]
    Certainly academically interesting!

    One of the more difficult situations was when the Manote Thiha attempted fire when you were near the wall:
    [​IMG]
    Ultimately, you were meant to wall jump over the boss. If a wall jump is attempted as fast as possible, sometimes you'll get hit. It's avoidable if you wait to jump over first flame, then wall jump. This way the first flame won't hit you during the wall jump, and you'll not be on the wall when the second one arrives.

    I designed some subtle things in favor of the player as well. The hitbox for the flame is only a single pixel wide:
    [​IMG]
    So the (however long it takes to actually avoid the danger) segment is smaller than it might appear at first.
    I made it so steadfast objects kill Ajna's X speed if she hits them with a jumping attack. Here's a gif that shows the difference:
    [​IMG]
    Normally in the air, you continue moving at the same horizontal speed if you're holding neither left nor right. After starting the axe swing, both left and right are released. In the left GIF, Ajna falls straight down after hitting the Manote Thiha. In the right GIF, Ajna continues traveling right until she lands and friction stops her. Why have this special case? If Ajna continued right after hitting the Manote Thiha, she'd just get hit. The Ahp gets knocked backwards making room for Ajna to land where it used to be. Not so with the Manote Thiha, hence the exception. That said... if the player continues to hold right, they will accelerate toward the Manote Thiha after having their horizontal speed zeroed. I think that's fair, they're actively steering there!

    Another behavior that's somewhat hard to prove with a GIF. The boss actively avoids putting you in inescapable positions with its body. It cannot go about 1.5 of its body lengths toward either wall to avoid cases where you run toward the wall, and it jumps after you right next to the wall. It jumping backwards on hit also makes the wall jump flame case slightly more rare.

    All of the above things are not things I expected players to notice, but I expected them to subtly help. And certainly, watching testers play, they did help.

    The Testing Experience

    I considered the boss to be "done". The fight looked like this:
    [​IMG]
    That lick? Not reactable. You can straight out-range it, though. And you know what? The boss also totally ends up too close to the wall in that GIF, for reasons related to code meant to prevent it. The Manote Thiha usually jumps backwards, but it knows if it jumps backwards here it will be too close to the wall. So it jumps forwards, making it too close to the wall... This was tweaked in later versions.

    Anyway, I could beat it consistently, the "fairness math" checked out, and I genuinely found it fun. It already had lots of tricks to make the fight go faster, but I also made sure I could beat it consistently in the "simple" way. I created "Indivisible Test Build 1" and sent it out. Hours later, I created "Indivisible Test Build 2", because I realized I messed up a debug command.

    It was sent to just four people. (Or maybe slightly more! But I only have records of four people actually testing it.) 3/4 were online friends I met in a particular art community. One was a person I never spoke to before, but that I contacted because they were reasonably familiar with Actual Indivisible. One of the cool things about NES development is you get deterministic input recording for free through emulators. I had all the online testers send recordings. I got back hours of footage. I also watched a couple of local friends play.

    The results were humbling. Only 2 of the 4 online people beat it. From what I remember, about half the local people beat it as well. Of the two online people that beat it, one took more than 7 hours of basically nonstop attempts. I watched in a private livestream. They had fun, but that was far outside the range of what I wanted! My goal was maybe 20 to 30 minutes of attempts, which is more or less like the original game.

    I actually ended up putting together a "Boss Coach" ROM for the person that attempted a lot. I mentioned earlier that the Manote Thiha and most enemies were initially designed to be played with player 2's controller. So I hooked that back up, sent it to them, and we played online with me as the boss to practice attacks in isolation.

    I was invested in helping people beat it, but the boss itself obviously had to change. I had inadvertently created a "Dark Souls Hard" boss when I was trying to match the difficulty of the original game.

    There were quite a few issues. One of the bigger unforeseen ones was actually the enemy summons:
    [​IMG] [​IMG]
    They fell almost immediately and made people panic. They couldn't damage Ajna for a while after they appeared, but the suddenness of the appearance made people commit to the axe in unsafe situations. The plan was always to have them float a bit before falling, but I figured this would be fine for testing. I was incredibly wrong.

    Ajna's range was also a relatively large problem. You can see me miss a jumping attack at a point in the left GIF above. This is why doing all the art first before putting it into the game is bad practice... I had a pretty good idea her range was too short, but tried to convince myself it'd be fine because changing the graphics was such an incredibly awful experience. (Less making them, and more getting them into NES ready formats.)

    Something also pretty unforeseen is that a lot of people moved in such a way that the boss ended up off-screen. To be clear, Test Build 1/2 had no sound effects. An off-screen boss was pretty dangerous...

    People also had difficulty reacting to the Manote Thiha's kick. One tester (from a later build) told me it was because the first visual frame looked like the hurt animation. They were right!
    [​IMG]
    All that reaction time stuff only matters if the danger is recognized as danger in the first place!

    There was a Test Build 3, but I don't think it was "officially" announced. I just stealthily updated the package.

    Test Build 4 was the next "major" round of testing. It was opened up to a decent amount more people that I didn't know, and no one leaked any of the things in the ROM that weren't talked about publicly. Love y'all!

    I made the following changes between Test Build 2, and Test Build 4 as far as boss gameplay things:

    1. Added music and sound effects. The help this provided probably can't be understated. It helped people with reacting to the kick, but also with the off-screen boss issue.
    2. Extended Ajna's range. It's hard to see this in real time, but here's a GIF for completeness, as well as one frame with a particularly large change:
    [​IMG] [​IMG]
    3. Added a "warning" icon to the kick animation. This helped with the similar looking animations.
    4. Added a target reticle to Ajna during the fire attack to make more clear that the fire is created where she is.
    5. Made it so the boss does not hurt Ajna while rising:
    [​IMG]
    Surprising, huh? This was done because people occasionally got hit while standing when the Manote Thiha tried to jump over them. I was never satisfied with any hitbox based solutions for this. On a modern platform, I'd probably ensure she'd get hit in the case of the above GIF, but it'd have required more state. Anyway, like the 1 pixel fire and steadfast hit speed kill, it's subtle unless you're truly aware of it.
    6. The enemy summons are no longer panic inducing:
    [​IMG]
    One more change where the help it provided can't be understated.
    7. Made the playfield smaller so it's slightly less likely for the boss to be doing off-screen nonsense.
    8. Tweaked the Manote Thiha's forward jump. A lot of people were getting tackled. The Manote Thiha is off-screen. It jumps forwards towards Ajna. People got hit, it wasn't really possible to see coming.
    9. Made a lot of enemy attacks slower which made the enemy summon segments for the fight easier.

    Here is a clip of the Test Build 2 and Test Build 4 version of the fights. (4 is on the right):

    [​IMG] [​IMG]

    I was pretty confident for this build too. After sending it out, people were now generally beating the boss, and in times that were what I was aiming for. I took short notes on each playthrough. Here are some examples (anonymous, don't worry!):
    I'll be honest, I was really hoping for someone to start actively using the kick reflect.

    People were getting similar times, and every new recording I received was like Christmas. (Will they beat the previous record?!) I'm definitely really, really glad I had people record input. Watching them gave me several epiphanies about how people learn in video games. I should note specifically: It was the input display. Had I only had raw video such that I couldn't see what buttons were pressed, I would not have learned the same things. It seems simple and obvious with hindsight, but in a game that looks like Castlevania, some people will never press up (or down). It was really interesting to see what things people did to start to learn the game.


    Three more test builds were created. 5 was probably another "stealth update" like 3. I possess no recordings of tester play for it. Very few people played it. 6 and 7 were basically the release build. The differences between this set of test builds and Test Build 4 were more polish than boss stuff.

    The biggest change from 4 to 7 was this:
    [​IMG]
    The Manote Thiha now shows where it will jump. This helped if it was off-screen, but also because there's only one jump animation. It became just a little more clear to see where it was headed.

    There was at least one tester who has strongly favored each kind of attack. (Jumping, Crouching, Standing.) And they all found success in very different ways, but also got caught by different things as a result of their choice. I'm pretty happy about that, I didn't exactly... plan for it, but it really ended up working.

    It was also cool to see some people really favor wall jumps, and some people really favor axe hang and the results of that. In general different people discovered different things in the game. Even if there were things they didn't know, what they figured out worked out for them. I watched over 24 hours of tester play in real time. (Shoutouts to the one person who made Ajna dance to the music for a little bit.)



    The Bug

    There was one annoying bug. It wasn't found by a tester. It drove me crazy for months. It was a happens-once-every-thousand-fights kind of a bug. And thus, it deserves its own section. One of the other reasons I had testers record their input was in case they ran into it. (No one did.) If someone had, I could have used their movie file to see absolutely everything that happened in the code from reset to the bug and found the cause.

    This was "the bug":
    [​IMG]
    The boss would sometimes hide far away from the slots it was intended to hide in. Why does this matter? When it unhides, it's confusing:
    [​IMG] [​IMG]
    Two of those GIFs are actually mentioned in the test package. And you may wonder, "If you have the GIFs, why did the bug need to be reproduced?"

    There was a very obvious tell when this bug was going to happen. The Manote Thiha would jump high, and land away from any of the slots. At that point, a GIF recording is possible, but it doesn't help me find what caused the bad jump to happen in the first place even if I debug from that point on. I started to try record all my gameplay. It never turned up in a recording.

    Somewhere around Test Build 4, I made some changes that made it happen less often (it was already rare)... but none of the changes seemed to logically fix it. I even put in a failsafe so that if it DID happen, the result would be less bad. (If the Manote Thiha starts to hide in the wrong place, its body is moved to the right slot. This way when it unhides, it will at least not appear someplace confusing.)

    I ended up complaining to someone about it. While reading the code to do so, I found it. The Manote Thiha jumps actually go through several states and the Manote Thiha can only start to jump from its idle state. A "backward" jump happens when the Manote Thiha is hit and jumps backwards to avoid more pain. (It goes less high.) There are four possible targets for a "forward" jump. Ajna, or any of the 3 slots. A "forward" jump very specifically can't go backwards because that looked weird (due to the different height). Suppose the Manote Thiha wants to jump to slot 1, but slot 1 is behind it. It will turn to face slot 1. Then it will jump. Enter Ajna. She's a moving target. So it's possible for her to switch sides as the Manote Thiha is turning towards her (or even during jump startup). Fine. In that case, the Manote Thiha will jump straight up. The position will also be changed if Ajna is too close to a wall. (To keep the Manote Thiha away from the walls as mentioned in an earlier section.)

    The Manote Thiha did jump straight up when this bug happened. But why, oh why, would any of the immovable slots ever cause that? And why, oh why, did it happen so rarely?

    Suppose you hit the Manote Thiha. Its health is now low enough that it needs to find a slot. The Manote Thiha cannot move. The slots cannot move. It chooses a slot. It turns towards it, if necessary. Then it jumps.

    Well, the Manote Thiha can move. But it can still only jump from the idle state. So say the Manote Thiha jumps backwards and you hit it in midair. Fine. It has to land before it can choose a slot. It turns towards it, if necessary, and jumps.

    The problem, as it turns out, was friction. Suppose the Manote Thiha jumps backwards. It lands, and when it lands its speed is not 0. Instead friction kills its speed over a few frames. Now suppose the Manote Thiha jumps backwards and you hit it in midair, and this hit is the hit that will make it choose a slot. Fine, it will land and choose a slot. Then it will turn toward the slot, if necessary. Then it will jump there.

    But now suppose the Manote Thiha jumps backwards, and you hit it in midair, and this hit is the hit that will make its health low enough to choose a slot, and that when it lands it chooses a slot, but during jump startup it moves such that a different slot is now closer AND that different slot is behind it. Well... then it jumps straight up.

    The changes I made that made the bug happen more rarely turned out to be decreasing the horizontal speeds of all the jumps. This meant friction would happen for fewer frames, which in turn made it much less likely for it to cause a different slot to be closer. The fix is easy: Kill horizontal speed during target selection/jump states.

    You might wonder (with all this hindsight), "Why not turn again before the actual jump?" Because it would have been possible to make the boss turn around forever, in theory, when it targeted Ajna. Yes, an exclusion could be made when Ajna is not being targeted. Many problems are easier to solve with hindsight!

    So. How are you feeling? You good? Need a glass of water? Well. The post would be done. Except there's a secret boss. Wait, come back!

    The Secret Boss

    Now's your chance to turn back if you don't want to spoil things even more than knowing it exists! Actual Indivisible has a secret boss. So NES Indivisible has it too. I spent a decent amount of time on the first version of the Manote Thiha's AI. Two weeks? Something like that. And I spent like... four hours on the secret boss' AI. Guess which ended up better?

    The secret boss' AI is basically unchanged from Test Build 2 until the release version. It had bug fixes... there were some graphical errors I had to write special cases for. But gameplay wise? Nah. It's basically the same.

    There is a funny looking cat in Skullgirls (a previous game from the developers of Actual Indivisible). It has a very low chance of popping out of Cerebella during her attack, Lock 'n' Load. It was doodled on a frame of the attack, and forgotten to be erased. Then it was put in the game officially. And that is the origin story behind the most powerful being in Indivisible.

    Behold, THE SCRIBBLE CAT!
    [​IMG]
    MEOW
    The Scribble Cat in Actual Indivisible has four attacks. Chomp, a claw swipe, fire breath and an earthquake. It has 9 lives. On its first life, its health drains extremely quickly, almost like a really weak enemy. On each subsequent life, the cat gets larger, and fiercer. It becomes more likely to do extremely damaging attacks, and the attacks themselves get stronger.

    It is an extremely difficult fight the first time! Much like the Manote Thiha, I drew all the required frames before implementing anything. Then I played the Scribble Cat in Actual Indivisible to see during which lives it gained which attacks and the general attack distribution.
    Then I put the frames in and gave it basic collision detection:
    [​IMG]
    It returns to its home planet because what is supposed to be the frame's visual offset is actually what's moving the cat. Normally this offset is undone, but I forgot to remove it, so the cat just moves inside a wall. (Collision checking only works for actual movement, because this type of change is supposed to be visual only.)
    Much like the Manote Thiha, I implemented all of its attacks to be controlled by player 2's controller:
    [​IMG]
    This was the result of an improper transfer of animation types. Frame number and exposure time typically share a byte. The fire breath animation needed a lot more exposure time and much fewer frames than most other animations, but I forgot to make the change for this in one place. The result is some of the frame exposure gets loaded as the frame number, loading garbage frame data. The claw animation is just because I had copied the claw's frame numbers as a base.
    The Scribble Cat and its fire breath are different objects. I made it so that when the Scribble Cat is interrupted during the attack, the fire dies down. It was a bit difficult, like the kick reflect for the Manote Thiha:
    [​IMG]
    In a process that continue to feel familiar, I put together a test fight with me controlling the cat with player 2's controller:
    [​IMG]
    When the cat dies, a little angle flies out of it T_T:
    [​IMG]
    This lets you keep track of what life you're on.
    Here's a GIF I desperately wanted to post while the game was still in development. I alluded to it when I mentioned the Ness Yo-Yo glitch in an earlier post, but I remained committed to keeping the scope of it secret:
    [​IMG]
    An attack that is going to put the attacker in hitstop should hit each object only once. If it could hit multiple times, it would and both objects would be stuck in hitstop forever. So each time Ajna attacks, she's dealt an attack number. When her attack is in range of something, it checks a slot on the hit thing's RAM to see what attack number is there.

    If the enemy's attack number slot holds the same value as the current attack number, the attack fails.
    If the attack number and attack number slot are different, it's a hit and the slot is then filled with the current attack number.

    Now, the location that holds the attack number is actually really small. With no other checks, this results in a bug (similar, but not quite the one shown in the gif). Ajna attacks. She is dealt the number one. Ajna attacks again. She is dealt the number two, and hits an enemy. That enemy now knows it got hit with two. Now Ajna moves away. She attacks until she's dealt one again. Then she moves next to the enemy and attacks. She's dealt two. The enemy was hit with two. So the attack misses, even if it's technically a different attack than the previous attack that was dealt two.

    There are only 16 different values that can fit in the attack slot, so Ajna wouldn't even have to roll a lot of times to make a miss if she knew how the system worked. To prevent that bug, I did a few things. I reserved 0 as representing free to be attacked by anything (more or less). I made Ajna's attack number roulette skip zero. Because an attacking Ajna will never have a zero dealt, any enemy with zero as its attack number will get hit by any attack Ajna throws out. When Ajna goes back to idle, she resets her roulette to zero, which in turn lets enemies know to also set their own attack slots to zero. Because an attacking Ajna never deals zero, all enemies can be sure she doesn't have an attack out they need to keep track of anymore. So they can safely set themselves to be hit by anything again.

    The cat in this gif doesn't set itself to zero, ever. (I was testing some other thing.) So, knowing Ajna's roulette resets to zero after being in idle, that should mean every attack she deals after returning to idle will be attack one. Because the cat doesn't reset to zero, this means it should get hit once, and NEVER GET HIT AGAIN.

    But the above gif shows... if she successively hits the cat while crouching, all the attacks will hit. Because crouch is not idle. And crouching attacks return to the crouching state, not idle. This means that even if the cat was programmed to set itself to zero, it wouldn't while she's crouched. Which means the bug I was trying to fight would happen. I crouching hit the cat. Turn the other direction. Attack 14 times. Turn back around... and miss.

    Here's that:
    [​IMG]
    The first attack has already hit. So she rolls all the attacks that will hit away from the cat until it loops back.

    The fix is simple: Also reset the roulette on returning to other idle states. This got me terrified of other things that may be lurking in the code.

    Here's the Yo-Yo glitch gif:
    [​IMG]
    This is a Super Smash Bros. Melee glitch. The bat missing near the end probably happens for similar reasons. (Preventing the "same" attack from hitting twice.)

    Suddenly, cats!:
    [​IMG]
    The be honest, I didn't note exactly why this happens, but I can't not include it. If I had to guess, I was changing something with how the angel was created and used the wrong object address to create the angel.

    Here are a couple of GIFs of me starting to implement the chomp attack AI:
    [​IMG] [​IMG]
    I was getting a feel for the best speed. And that's actually all I've got for "in development" GIFs for the Scribble Cat. It really was written pretty quickly.

    The idea for each attack came to me basically the second I decided to adapt the cat. In Actual Indivisible, the chomp has the Scribble Cat run up towards you and bite. Done exactly the same. In Actual Indivisible, the fire breath has the cat run up toward you and breathe fire. Done exactly the same. That leaves the quake and cat claw. For the earthquake, I did the stereotypical video game thing. If you're on the ground, you'll get damaged. If you're not, you won't.
    [​IMG]
    That leaves the cat claw which ended up being my favorite attack. There's a lot to talk about! In Actual Indivisible, the cat creates this comically large wind swipe:
    [​IMG]
    In NES Indivisible, the design behind the huge claw was to force you to dash away from the cat and towards the opposite wall to wall jump over it.
    [​IMG]
    This is super fun!

    Because the cat is a very hard to get to secret boss, I figured it was fine to assume people who fought it would know how to dash. (The claw moves at dash speed, so you can't outrun it.) This design was broken in two ways, one good, one bad.

    The design behind it was meant to force the wall jump. But it's possible to jump over it regularly:
    [​IMG]
    Because it is possible, some players figured that must be the solution. And it's pretty hard to do consistently. (You can jump over it when it's not fully grown, too. That was known.) Similarly, one tester thought the axe hang was the intended solution:
    [​IMG]
    This is maybe a bit easier, but still not quite what I wanted.

    One option that I had was making the projectile higher to make these dodges impossible, forcing players to find the "right" one. This would have had two negative effects.
    1. Players who did not know how to dash would be slightly more out of luck.
    2. It makes the intended solution harder too.
    I decided not to change it.

    One of my local friends found a way to dodge it that was 100% unintended, and I LOVED IT!:
    [​IMG]
    Dude just no fear jumped over the cat. I couldn't stop laughing! Jumping over the cat is also good for the fire breath, but I never thought of it for this.

    The fight is more or less: Choose an attack of the ones that are available for the current life. If hit, jump either forwards or backwards (in later lives), whichever gets it further away from Ajna, but not too close to a wall. In early lives, the cat's attacks can be interrupted by hitting it. In later lives it has "super armor". (Getting attacked will still damage it, but what it's doing is not interrupted. You can always interrupt it by "killing" it, though.) Its vertical launch distance (from attacks like crouching axe) also gets less intense as time goes on until it is steadfast, like the Manote Thiha.

    This is unrelated to anything:
    [​IMG]
    But it came up while recording and I had to share it. Great dodge!

    The cat has some silly exceptions too. One is a gentle wink at the original game, one is just to let the player know I thought of it. Remember the indefinite axe hang?:
    [​IMG]
    In the beginning of the Scribble Cat fight, it can only chomp. This can't hurt you if you axe hang. If you do it long enough, the Scribble Cat will earthquake to knock you off the wall, even in earlier lives.
    [​IMG]
    The Manote Thiha also has an "I thought of that" behavior...

    The exception that's a wink to Actual Indivisible is that barehands is better than the axe for the fight. In Actual Indivisible, Ajna's special when she doesn't have the axe equipped allows her to heal. I won't say this is straight "better" for that version of the Scribble Cat, but it's certainly pretty good and doesn't necessarily come to people without being told.

    In NES Indivisible? Axe and barehands do the same amount of damage to the cat. And hands are faster, and have less cooldown. Is this good game design? I mean... naaaah. But I really liked that each life took exactly that number of hits.

    The other cat exception was put in later than Test Build 2. I violated the sacred law of hitstop to change the animation frame to the chomp one for contact damage. It is adorable:
    [​IMG]
    It's subtle because an actual chomp looks similar, but even if the cat is walking toward you to breathe fire or you fall on it, this will happen.

    Here are the gameplay changes I made since Test Build 2:
    1. Gave more startup to Cat Claw
    2. Gave 5 frames more cooldown to Cat Claw. (Very little, just to make the Cat Claw->quake combo less likely to be unfair.) The intended way to dodge the claw is to dash toward the opposite wall, and wall jump. The original timing made it so that if the cat started the earthquake after cat clawing, you'd basically get hit right after you hit the ground from the wall jump.
    3. Made the Warning! icon appear when the Scribble Cat starts a quake. (The same one used for the Manote Thiha's kick.)

    In Actual Indivisible, the cat is a fearsome challenge. In mine, it's almost certainly easier than the Manote Thiha even if you don't know about the hands thing. I actually had testers familiar with Actual Indivisible complain that it was too easy. Unfortunately most people will never play against it. How does one get to the cat, you ask? Why, all you have to do is this:
    [​IMG]
    Which is exactly like Actual Indivisible. (In NES Indivisible you can also die with very specific timing, but that's not... really any easier.) Defeating the Manote Thiha gives you a new ability, but you have to get back to the rest of the map to use it to find the cat.

    I'm very happy with how the Manote Thiha fight turned out, while simultaneously thinking it's still too hard. People still tell me they can't beat it. But man... I really love it. I still play through it on occasion to kill time this long after. I have ideas for fixes, I had some even before release... but eventually... you have to call the thing done.

    And there's the post. If you take anything away from it, it should be that input recording is awesome and worth your time. Even if you don't get it for free like an NES developer does, it's probably worth implementing some kind of replays in your engine. Thanks for reading!
     
    Last edited: Aug 30, 2019

Share This Page

Facebook:

Users Viewing Thread (Users: 0, Guests: 0)