Handling Enemy AI in 2D Metroidvania

How do games handle unique enemy behavior in a 2D Metroidvania? What’s the best practice?

Like in Castlevania for example, every enemy had a unique pattern. They weren’t simple like modern metroidvanias. Would it be 1 common script to deal with common stats and features, then 1 other script to deal with unique behavior for each and every enemy?

For example:
An enemy that can jump and damage a player with contact damage.
Another enemy that can jump, then attack the player if near and cause damage.
Another enemy that can jump, then attack simultaneously in the air and cause damage.

These 3 enemies CAN share a jump script - but the attacking portion is unique. One does not attack at all, one attacks only after landing near the player, one attacks only in the middle of the jump.

Do I handle all the different attack scenarios in one script? because I can easily see this become a giant script down the line and was thinking it might not be a best practice. Any advice appreciated here!

They are probably just a bunch of scripted motions… a ton of AI on those great metroidvania games was actually just super-simple, but so well executed and combined with the level layout and other enemies in order to give such an enduring challenge.

You could use a spline editor to generate some interesting pre-made curves, then just play them back into the enemies, either rotating them as well , or just translating them.

Even something as simple as waypoint patrolling for one mode, then “oh I see the player” and they just lunge until you’re out of range, then they un-lunge back to their waypoints.

That would work except not so well for pixel art sprites.
I did create separate ‘AI’ behaviors like Flyer, Jumper, Patrol, Pursuit and have varying stats in these. Then there’s one common enemy class that has basic functions. I guess there isn’t really one approach to this but just extend upon those base AI behavior scripts and go from there. Like if a monster’s basic function is flying, extend various attack/reaction scenarios. Or if it’s basic function is to patrol, extend various attack/reaction scenarios.