Implementing Magic Shots

Lolo’s only “weapon” against the enemies in his adventures are the magic shots he collects from certain heart frames. Most enemies struck by a magic shot are temporarily encased in an egg which Lolo can then push around for cover just like an emerald frame. Magic shots are integral to his success, so let's look at how they work.


Each heart frame is either magically enchanted or it isn't. Each magic heart frame gives Lolo two magic shots when collected, and the “collection chirp" sound is slightly higher-pitched from regular heart frame chirps to help indicate the collection of magic shots.


Once Lolo has magic shots, players need only press a button and Lolo will shoot eggifying magic. The magic shot will travel at high speed until it encounters an obstacle. If the obstacle is an eggable entity like Snakey or Alma, then the entity will temporarily become an egg. If the target is a crystal frame (featured only in the Windows 95 games) then the magic shot will rebound at 90 degrees off the crystal frame. Fun fact– magic shots can also collide with Gol's fireball in some games, neutralizing both projectiles. Sweet!



The story so far



Like all entities in these games, the magic shot travels along the invisible grid lines of the world, and it moves four pixels per frame (four times faster than Lolo). Unlike anything else, magic shots exhibit unique pathing entirely their own. Specifically, it will not get stopped if it only skirts along the edge of an obstacle. It will not be stopped by obstacles touching at corners, it will only be stopped by a "completely blocked" path.



Strange, but at least it’s consistent, Don



I’ll repeat, this quirky behavior is unlike any other collision algorithm in Eggerland. Why you do like that, HAL? Even Gol's fireball can't skirt past half-spaced obstacles. Yep, totally unique behavior we will have to code up, no reuse. Yay quirkiness.


But I have a plan, let's see what you think. Every entity in Eggerland has a collision box that determines where it is and where it can go next (check out Medusa’s and Don’s stuff if you want a collision refresher). Lolo's code uses his collision box to know whether or not he’s overlapping with a wall, understanding that Lolos generally do not phase through solid matter. Alas, Lolo never learned the art of noclip.


So far, one collision box has worked for other entities but simply will not give us enough information this time; we need to compute the difference between skirting by the side of an obstacle and running head-on into a solid wall. So let’s use two collision boxes! If the magic shot checks two boxes, then we can detect the difference.



The magic shot only registers a collision when both collision boxes are red i.e. are overlapping an obstacle


Many modern games use complicated combinations of hitboxes for location-based damage, or to make sure a bullet can pass through the space between a target’s legs instead of making contact. Check out this video by TheHappieCat for some nice visual depictions. I've already implemented a Rectangle class in the past, so let’s reuse that to represent our multiple collision boxes. That Rectangle class is actually coming quite in handy, I may look at older code and see what it can improve, don’t let me forget that. For now, two collision boxes, two Rectangles seems good.


So once we detect a collision, we need to notify the target they've been hit by a magic shot. We need to identify what exactly got hit, but having two collision boxes makes that difficult. For example, look at this corner case I found in Departure to Creation:



Snakey 1: “I think it was you.”
Snakey 2: “No no, it’s your turn.”
Snakey 1: “He was definitely looking at you.”
Snakey 2: “No I insist…


Did you see that!? The magic shot detected a valid collision and disappeared as expected, only nothing got eggified. Why?


Well… which one should have gotten eggified? Probably shouldn't be both or players might exploit that to perform more eggifications per magic shot. It seems the developers at HAL decided neither would get eggified, which I think is a reasonable move in a game where puzzles sometimes rely on precise resource management. If we want to reproduce HAL’s behavior, maybe we can find the first eggable entity that intersects both collision Rectangles and call that the most valid target.


I recommend we make every game entity implement an eggify() method so that each entity can choose how to respond to eggification. Most entities, like walls or trees, will do absolutely nothing when eggified, but Eggable entities could use this eggify() method to transform into an egg.

  • Eggs could use the method to get blasted away.

  • Eggified fireballs will enter their splashing state when they get eggified.

  • Crystal frames will absorb the magic shot and refire it in the new rebound direction.

  • What else?


There's also Medusa and Don Medusa. In most Eggerland and Adventures of Lolo games, it's simply not possible to egg Medusas or Don Medusas, even if you timed a magic shot just right and managed to hit a Medusa or Don Medusa. *whispers* (By the way, this lack of eggability is why I posit that the Medusas’ logic is less complicated than all others, even Snakey’s.)



It wasn’t just a joke, a pushable Snakey is its own complicated work


There is a special one-time condition in one puzzle in Eggerland: Meikyuu no Fukkatsu requiring a magic shot to strike Don, but even that doesn’t egg Don, it just causes a special stopwatch item to spawn.



Early Eggerland games weren’t just puzzle games, they were labyrinths; one giant puzzle made up of individual puzzles, and sometimes the individual puzzles had special puzzles within them


This utter lack of eggability is also acknowledged in Adventures of Lolo 3 (or Adventures of Lolo 2 in Japan) where the boss versions of each monster get egged upon defeat, all except for Medusa and Don Medusa, who just... explode.



This is basically the deep lore of the Lolo franchise. It’s a shallow pool.


Okay, one final wrinkle: Revival! Eggerland and its demo Eggerland Episode 0: Quest of Lala change this canon to make their new crystal frames work. Except those new games also make it possible to eggify Don Medusa with a well-timed shot.



Don didn’t have enough problems and corner cases, and Windows happily fixed that


Puzzles that were literally unsolvable (like the gif above) could suddenly be solved with a well-timed shot. This breaks backwards compatibility in big and unintended ways, so I don’t want this behavior in Eggerworld.


For full transparency, I am going to build another state machine for the magic shot much like the state machines we made for Alma, Leeper, and Skull. Magic shots will transition between the “flying forward” state and an “inactive” state. Overengineered you say? Maybe, but it is super easy to copy-paste existing state machine stuff from Alma’s logic.



If you know, you know


With that, Lolo is ready to fire magic shots! I think so, anyway. There are almost always bugs, but the best way to find bugs is to create them first. That's a good policy, right? Right?


Comments

Popular posts from this blog

Demo is here!

Who Is This For?