I've figured out a bit more about the enemies, but there's definitely going to be some difficult challenges ahead. I managed to isolate where in memory a particular moo's position was being stored (and freezing it made the enemy unable to move), but the next time I started up the game, the enemy position was NOT stored in the same place, even at roughly the same point in the game.
This very strongly suggests something I already suspected: the enemies are being allocated dynamically (if you're not familiar with that concept, there's a pretty good explanation at
https://en.wikipedia.org/wiki/Memory_management#DYNAMIC). Basically, the game says "find me some empty memory to reserve for this chunk of data" and another function does this and passes address of the newly-reserved memory back to the game. Thus, in order to reliably locate enemy data, I'll need to find the chunk of code that allocates memory for the enemies and read the memory address that gets sent back.
One thing I'm not completely sure of is whether the game allocates memory for each individual enemy on the fly, or if it allocates a big block of memory (array) for a whole list of enemies at once. I'm guessing it allocates memory for each enemy based on two things. First, it saves memory to do it this way; if we reserve memory for a bunch of enemies at once, and there are only one or two enemies that are actually "active," there's a bunch of unused memory that the game can't use for anything else. Second, if the enemies are all allocated in advance, they'll almost certainly be evenly spaced in memory, but this doesn't seem to be the case. I found the position value for two different enemies at 0x0C06E0 and 0x0BFF98, which are 0x000748 apart from each other, but jumping ahead by that same value again (to 0x0C06E0) didn't seem to yield anything useful.
In an ideal world (for me at least), there'd be a single chunk of memory at a fixed location for all of the enemies, but it doesn't seem like this is the case. That said, enemy data also needs to be stored in the ROM itself (at least the enemy's initial position, type, etc.), so at least that will exist in a fixed location. I bet if I can find an enemy's first position value in memory, I'll be able to search for that same value in the ROM's data. Unfortunately it's going to be tough to set a breakpoint for the first time that value is set, since I won't actually know WHICH value it is that's going to be set...
EDIT: One other thing I'm curious about is how the game keeps track of the "list" of enemies. A common approach is to use a "linked list," where each chunk of enemy data would also store the memory location of the NEXT enemy on the list. That way in order to loop through all of the enemies, the game would just need to know the location of the first enemy and then follow the chain until it reaches the last enemy. The last enemy would just have a null/dummy value like 0 for the address of the non-existent "next" enemy, so that the game knows it's reached the end of the list.