First random bit of Ecco II code analysis.
The Asterite.
Curiously enough, he is actually stored as two halves inside two 32-bit variables at RAM addresses
0xD434 and
0xD438. Every globe is represented by a single bit in those: e.g.,
0x0F is 4,
0xFF is 8, etc., up to 32 in each helix.
Code: Select all
// Global variables to store Asterite's status
// RAM addresses 0xD434 and 0xD438
uint32_t gAsteriteGlobesLeft, gAsteriteGlobesRight;
It is possible by manipulating those variables to spawn an "asymmetrical" Asterite, as well as making "holes" in him: the game does not mind this. However, none of the functions that I have met so far appear to be using this and in fact the one responsible for counting globe pairs will return -1 if pairs mismatch. It's possible that they were intending to manipulate individual globes, such as in Ecco 1, but feature ended up never used.
Storing data like this is very inefficient otherwise, but they can get away with this since that is really only used when saving the game in a password and restoring it from that.
The following is a reconstruction of the function at ROM offset
0xB0BA4 that counts the globes:
Code: Select all
int countAsteriteGlobePairs(void) {
int retval = -1;
uint32_t MASK = 0x80000000;
int16_t globeCount = 0;
if (gAsteriteGlobesLeft == gAsteriteGlobesRight) {
for (uint16_t i = 32; i > 0; i--) {
if ((gAsteriteGlobesLeft & MASK) != 0) {
globeCount++;
}
MASK = MASK >> 1;
}
retval = globeCount;
}
return retval;
}
Function to populate Asterite at ROM offset
0xB0BD8:
Code: Select all
void setAsteriteGlobes(uint8_t numPairs) {
uint8_t i;
uint32_t MASK = 1;
gAsteriteGlobesLeft = 0;
for(i = numPairs; i > 0; i--) {
gAsteriteGlobesLeft |= MASK;
MASK = MASK << 1;
}
gAsteriteGlobesRight = gAsteriteGlobesLeft;
return;
}
Following that is a function at ROM offset
0xB0BFC that initializes Asterite, setting both globe variables to 1, but it also takes care to fill 196 bytes at
0xD35E with zeroes. It actually makes more sense to post the raw disassembly of it for now since it's very short:
Code: Select all
clearAsteriteGlobes:
moveq #0x0,D1
lea (DAT_ffffd35e).w,A1
movea.w #0x31,A0
moveq #0x0,D0
.loop:
move.l D0,(A1)+
addq.w #0x1,D1w
cmp.w A0w,D1w
blt.b .loop
moveq #0x1,D0
move.l D0,(gAsteriteGlobesLeft).w
move.l D0,(gAsteriteGlobesRight).w
rts
Essentially a
memset() and two assignments, really. I have not yet worked out what said location does exactly but so far my hunch is that the actual globe objects are to be stored there for animating them. This array is referenced in a lot of functions:
Code: Select all
fClearAsteriteGlobes:000b0bfe(*),
fClearAsteriteGlobes:000b0c08(W),
FUN_000b1536:000b1542(*),
FUN_000b1536:000b154e(*),
FUN_000b1554:000b1562(*),
FUN_000b1554:000b156e(*),
FUN_000b1574:000b1580(*),
FUN_000b1574:000b158c(*),
FUN_000b1f60:000b20f8(*),
FUN_000b2208:000b2260(*)