After last time's slow start into the collision detection code things are going to be more interesting this time. The second function call from the main collision detection code contains quite a lot of code (at least indirectly because it calls lots of other functions). So much in fact that a decently sized chunk of ROM bank 15 contains nothing but code and data that's used from that function. Thankfully it's not necessary to explain all, or even most of it because a lot of code is very similar and I can skip over it without explaining it any further. You'll see later why exactly that's the case.
OK, let's begin. The main part of the function I'm going to discuss in this update is located between offset $A66B and offset $A68E.
There are two checks at the beginning, if neither of these are passed the function instantly returns. The first check once again tests if the hour glass is active. If it's inactive the second check comes into play. The sprite ID of the current sprite ($2CC,X) is used to address the table at $B544. This table stores a one byte value per sprite that contains the general category the sprite falls into.
Valid values for bytes in that table are:
$00: Sprite is a small monster
$01: Sprite is a reward (gold or meat)
$02: Sprite is a NPC
$03: Sprite is some kind of non-interactive animation, for example the death animations of the monsters or fountains.
$04: Apparently unused; not one byte in the table has value four.
$05: Sprite is an item
$06: Sprite is some kind of magic
$07: Sprite is a large monster
Apparently the second check determines whether or not the current sprite is a monster. That makes sense because only monsters are frozen by the hour glass.
CODE:
<br />$A66B-> AD 2A 04: LDA $42A ; Hour glass active?
<br />$A66E-> 30 9: BMI $A679
<br />$A670-> BC CC 2: LDY $2CC,X
<br />$A673-> B9 44 B5: LDA $B544,Y ; Sprite is a monster?
<br />$A676-> D0 1: BNE $A679
<br />$A678-> 60: RTS
<br />
If at least one of the two checks succeeded the sprite can be moved. This is done (indirectly) in the part that comes now, the main part of that function.
The next two sprite data arrays are introduced here. The first one ranges from $354 to $35B and the second one follows right thereafter ($35C - $363). The combination of the two values ($354,X is the lower byte; $35C,X is the upper byte) forms a pointer to what I call the sprite description table. This table contains meta-data that describes how the individual sprite types behave. More on this later when the rest of the function was discussed. For now it's sufficient to know that the sprite description table contains top level rules (or main rules) and (depending on the top level rule) sub-rules.
In the first part of the code the top level rule of the sprite's behavioral meta-data is loaded and executed.
CODE:
<br />$A679-> AE 78 3: LDX $378
<br />$A67C-> BD 54 3: LDA $354,X ; Form pointer in $CA/$CB
<br />$A67F-> 85 CA: STA $CA
<br />$A681-> BD 5C 3: LDA $35C,X ; Form pointer in $CA/$CB
<br />$A684-> 85 CB: STA $CB
<br />$A686-> 20 BC A6: JSR $A6BC ; Load rule and execute it
<br />
Afterwards the currently active sub-rule (as written by the function call to $A6BC above) is loaded from the next sprite data array ($2D4 - $2DB). This sub-rule is then used as an index into the sub-rule table ($A5E7) which contains pointers to the actual code that belongs to a given sub-rule. The check that makes sure that the sub-rule ID is not larger than $84 (or better $42) only leads to some error-correcting code I'm not going to discuss here.
CODE:
<br />$A689-> BD D4 2: LDA $2D4,X ; Get sub-rule
<br />$A68C-> A: ASL A
<br />$A68D-> A8: TAY
<br />$A68E-> C0 84: CPY #$84
<br />$A690-> B0 F: BCS $A6A1 ; Check for validity
<br />$A692-> A9 A6: LDA #$A6
<br />$A694-> 48: PHA
<br />$A695-> A9 A0: LDA #$A0
<br />$A697-> 48: PHA
<br />$A698-> B9 E8 A5: LDA $A5E8,Y ; Address sub-rule table
<br />$A69B-> 48: PHA
<br />$A69C-> B9 E7 A5: LDA $A5E7,Y
<br />$A69F-> 48: PHA
<br />$A6A0-> 60: RTS ; Go to offset from table
<br />
That's the end of the function so let's now have a look into the function at $A6BC which is used to load the main rule of the current sprite. Remember that $CA/$CB contains an offset to the beginning of the sprite's sprite description table entry.
CODE:
<br />$A6BC-> A0 0: LDY #$0
<br />$A6BE-> B1 CA: LDA ($CA),Y ; Load first byte
<br />$A6C0-> C9 FF: CMP #$FF
<br />$A6C2-> F0 B: BEQ $A6CF ; Entry is empty
<br />$A6C4-> A: ASL A
<br />$A6C5-> A8: TAY
<br />$A6C6-> B9 D9 A6: LDA $A6D9,Y ; Address main rule table.
<br />$A6C9-> 48: PHA
<br />$A6CA-> B9 D8 A6: LDA $A6D8,Y
<br />$A6CD-> 48: PHA
<br />$A6CE-> 60: RTS
<br />
The table offset $A6D9 contains eight entries for eight top-level rules. What exactly these rules do is the topic of the next two updates.