Pidgeot: The games were planned to a meticulous detail; memory management was an entirely manual process - and I don't mean calling malloc/free, I mean manually designating memory locations/areas to avoid the overhead of an automatic memory manager (with only 128KB of RAM, that can be very significant).
Once you're at that level, C and assembly isn't all that different.
There's also no reason you can't write complex stuff in assembly. RollerCoaster Tycoon (which is from 1999!) was almost pure assembly; C was only used to interface with the OS libraries.
I know how critical it can be while writing code. 128K honestly isn't enough room to justify using malloc/free, you'd rather just assign 256 byte blocks and have 16 of them available, then using one per enemy data, and stuff like that. Most often the block would never be relocated/reassigned, and as you aren't dealing with data that needs much of sorting that problem isn't really present. From there it's well made structs that are compact and hold all the data you need. For bullets and bullet hell type of stuff, usually x,y location, sprite & speed & direction is probably all that's needed and once it's off the screen it gets recycled, swapping with something that isn't empty once per loop.
Although i know the general of crunching assembly code and structs and management, i haven't done a full game so... *shrugs* But i have done an assembler that used 320k of memory, or small com utilities using no more than 64k (
quite often less than 1k beyond the programmed code).
oh well...