Prev: D4B2 Up: Map Next: D5D4
D4FC: Move and draw the room's foreground scenery items
Follows previous section at D4B2
This routine handles the room's foreground objects - originally set up at C501, and stored in data sets at 7F01.
  • Foreground object horizontal position and movement speed is calculated at 2x the values of the rest of the on-screen scenery. This produces a parallax scrolling effect.
  • At Maroc's full speed (32 or -32 depending on left/right direction) foreground scenery objects move 16 pixels, other scenery objects move 8 pixels
  • Unlike the other room elements, foreground scenery items move in whole character or 2 character steps
  • Foreground scenery horizontal position is stored in 1 character/8-pixel steps, rather than 4-pixel/half-character steps like other items
foreground scenery movement
D4FC LD A,($EAB7) Get room number
D4FF CP $E0 Is it a vertical tunnel room ( >= room 224)?
D501 JP NC,$D6D2 If so, no foreground objects - skip this routine
D504 LD HL,($EB70) Get pointer to foreground scenery room object data (7F01)
Copy item set data bytes into various working buffer addresses:
D507 LD ($EABE),HL Store pointer to object data in address pointer buffer
D50A LD A,(HL) First byte of data set
D50B INC HL
D50C CP $FF Is it end-of-data?
D50E JP Z,$D5D4 If so, skip out of this routine
D511 LD B,A Store first byte in B register (used as a counter and checked later at D581)
D512 LD A,(HL) Second byte of data set
D513 INC HL
D514 LD ($EB47),A Store second byte of set
D517 LD A,(HL) Get third byte of set - item's horizontal position in room (in character/8-pixel steps)
D518 INC HL
D519 LD ($EB48),A Store horizontal position for item
D51C LD A,(HL) Get fourth byte of set
D51D INC HL
D51E LD ($EB49),A Store byte 4 of set
D521 LD A,(HL) Get fifth byte of set - item's vertical position from top of playing area (in pixels)
D522 INC HL
D523 LD ($EB4A),A Store vertical position for item
D526 LD ($EAD2),A Store in second buffer
D529 LD E,(HL) Get address pointer to item graphics
D52A INC HL
D52B LD D,(HL)
D52C INC HL
D52D LD ($EACD),DE ...and store in graphic address pointer buffer
Convert horizontal position from characters to pixels:
D531 LD HL,($EB47) Get horizontal co-ordinate in 8-pixel/character steps (high byte = H register the important bit)
D534 LD D,H Copy to DE register pair
D535 LD E,L
D536 ADD HL,HL x 2
D537 SBC A,A Use the carry flag to identify whether it's a negative or positive offset (left/right)
D538 ADD HL,HL x 4
D539 RLA The RLA rotates increase (or decrease if negative) the accumulator, and this gives us an idea of which screen (i.e. left/right of the current viewport) the scenery object is in
D53A ADD HL,HL x 8
D53B RLA
D53C LD ($EAD4),A ...Store the rotated byte indicating horizontal screen/viewport number in current room
D53F LD A,H The high byte of HL contains the rest of the horizontal position of the object
D540 LD C,A
D541 LD ($EAD3),A Store it
Check Maroc's horizontal movement speed/direction and move the foreground scenery objects accordingly:
D544 LD A,($EB04) Maroc's horizontal movement speed
  • Negative values = Maroc is moving right (so scenery is moving left)
  • Positive values = Maroc is moving left (so scenery is moving right)
D547 LD L,A
D548 RLA
D549 SBC A,A Using an RLA followed by a SBC means the carry flag indicates left/right direction using the H register (e.g. 255 = Maroc moving right, 0 = Maroc moving left)
D54A LD H,A Store this value in the high byte (H), which will cause an addition/subtraction in the next instructions, depending on left/right direction.
D54B ADD HL,HL x 2
D54C ADD HL,HL x 4
D54D ADD HL,HL x 8
D54E ADD HL,HL x 16 (this is the extra that moves the foreground scenery 2x faster than other room elements)
D54F ADD HL,DE Add speed offset to horizontal screen position
D550 LD ($EB47),HL ...and store
The high byte (H) of the calculation calculated byte is a character square co-ordinate, the low byte (L) containing a fractions/remainder value. Multiply by 8 to convert to pixel values.
D553 ADD HL,HL x 2
D554 SBC A,A Use the carry bit to determine whether the offset value is negative or positive (depending on direction)
D555 ADD HL,HL x 4
D556 RLA
D557 ADD HL,HL x 8
D558 RLA
D559 LD ($EACC),A Store the high byte - indicating negative (255) or positive (0)
D55C LD A,H And the low byte, containing the horizontal pixel co-ordinate
D55D LD ($EACB),A
D560 CP C Has the scenery item's horizontal position changed at all?
D561 JR Z,$D565
D563 INC B If so, increment a flag in B register
D564 INC B
Check vertical movement speed/direction and move the foreground scenery objects accordingly:
D565 LD HL,($EB49) Get vertical screen pixel co-ordinate
D568 EX DE,HL Copy into DE register
D569 LD A,($EB05) Get vertical movement speed/direction (negative = Maroc moving down, positive = Maroc moving up)
D56C LD L,$00 Clear L register
D56E SRA A Divide speed offset by 2...
D570 RR L Rotate carry remainder offset into L register
D572 SRA A Divide speed offset by 4...
D574 RR L Rotate carry remainder offset into L register
D576 LD H,A
D577 ADD HL,DE Add the offset to the vertical pixel position
D578 LD ($EB49),HL ...and store new position.
D57B LD A,H Has the scenery item's vertical position changed at all?
D57C CP D
D57D JR Z,$D581
D57F INC B If so, increment a flag in B register
D580 INC B
Check if either horizontal or vertical position has changed - the B register has been updated if so:
  • 0 = neither horizontal or vertical position changed
  • 2 = either horizontal or vertical position changed
  • 4 = both horizontal and vertical position changed
D581 LD A,B
D582 CP $02
D584 JR C,$D5A2 Carry here means neither position has changed - no need to erase anything so skip the next few instructions
The item has moved, so it'll need erasing at its pre-move position:
D586 LD A,$00 Set draw/erase flag to 0 (ERASE)
D588 LD ($EACF),A
D58B CALL $DDA1 Erase the foreground scenery item
D58E LD A,($EACB)
D591 LD ($EAD3),A Copy the item's calculated horizontal (pixel) screen position into working graphic buffer
D594 LD A,($EB4A)
D597 LD ($EAD2),A Copy the item's calculated vertical (pixel) screen position into working graphic buffer
D59A LD A,($EACC)
D59D LD ($EAD4),A Also copy the horizontal co-ordinate high byte
D5A0 JR $D5AB
Check for item movement again:
D5A2 CP $00
D5A4 JR NZ,$D5AB
D5A6 LD ($EAD5),A Flag indicating whether (any part of) graphic needs drawing on screen - nothing's changed movement-wise since last check, so set to zero
D5A9 JR $D5B3 ...and skip draw routine
Item needs drawing on screen:
D5AB LD A,$01 Set draw/erase flag to 1 (DRAW)
D5AD LD ($EACF),A
D5B0 CALL $DDA1 Draw the foreground scenery item
Copy scenery item data into data sets at 7F01
D5B3 LD HL,($EABE) (Copy of) pointer to scenery item data at 7F01
D5B6 LD A,($EAD5) Flag indicating whether (any part of) graphic is visible on screen
D5B9 LD (HL),A Store in (first byte of) scenery data item
D5BA INC HL
D5BB LD A,($EB47)
D5BE LD (HL),A Put horizontal object position overflow/precision offset into byte 2 of set
D5BF INC HL
D5C0 LD A,($EB48)
D5C3 LD (HL),A Put horizontal object position into byte 3 of set
D5C4 INC HL
D5C5 LD A,($EB49)
D5C8 LD (HL),A Put vertical object position overflow/precision offset into byte 4 of set
D5C9 INC HL
D5CA LD A,($EB4A)
D5CD LD (HL),A Put vertical object position into byte 5 of set
D5CE INC HL Move pointer along to next data set item at 7F01
D5CF INC HL
D5D0 INC HL
D5D1 JP $D507 Continue to deal with (move, erase and draw) foreground scenery items
Next routine is at D5D4 (after all foreground scenery items dealt with)
Prev: D4B2 Up: Map Next: D5D4