Jet Set Willy: Routine at 91BE

| Routines

91BE: Draw the rope, arrows and guardians in the current room

Used by the routine at 89AD. Draws the rope, arrows and guardians in the current room to the screen buffer at 6000.
91BE | LD IX,$8100 | Point IX at the first byte of the first entity buffer at 8100
The drawing loop begins here.
91C2 | LD A,(IX+$00) | Pick up the first byte of the current entity's buffer
91C5 | CP $FF | Have we already dealt with every entity?
91C7 | RET Z | Return if so
91C8 | AND $07 | Keep only bits 0-2 (which determine the type of entity)
91CA | JP Z,$93B3 | Jump to consider the next entity buffer if this one is not being used
91CD | CP $03 | Is this a rope?
91CF | JP Z,$92A4 | Jump if so
91D2 | CP $04 | Is this an arrow?
91D4 | JR Z,$9237 | Jump if so
We are dealing with a horizontal or vertical guardian.
91D6 | LD E,(IX+$03) | Point DE at the entry in the screen buffer address lookup table at 8200 that corresponds to the guardian's y-coordinate
91D9 | LD D,$82
91DB | LD A,(DE) | Copy the LSB of the screen buffer address to L
91DC | LD L,A
91DD | LD A,(IX+$02) | Pick up the guardian's x-coordinate from bits 0-4 of the third byte of its buffer
91E0 | AND $1F
91E2 | ADD A,L | Adjust the LSB of the screen buffer address in L for the guardian's x-coordinate
91E3 | LD L,A
91E4 | LD A,E | Copy the fourth byte of the guardian's buffer to A
91E5 | RLCA | H=0x5C or 0x5D; now HL holds the address of the guardian's current location in the attribute buffer at 5C00
91E6 | AND $01
91E8 | OR $5C
91EA | LD H,A
91EB | LD DE,$001F | Prepare DE for later addition
91EE | LD A,(IX+$01) | Pick up the second byte of the guardian's buffer
91F1 | AND $0F | Keep only bits 0-2 (INK colour) and 3 (BRIGHT value)
91F3 | ADD A,$38 | Push bit 3 up to bit 6
91F5 | AND $47 | Keep only bits 0-2 (INK colour) and 6 (BRIGHT value)
91F7 | LD C,A | Save this value in C temporarily
91F8 | LD A,(HL) | Pick up the room attribute byte at the guardian's location from the buffer at 5C00
91F9 | AND $38 | Keep only bits 3-5 (PAPER colour)
91FB | XOR C | Merge the INK colour and BRIGHT value from C
91FC | LD C,A | Copy this attribute value to C
91FD | LD (HL),C | Set the attribute bytes in the buffer at 5C00 for the top two rows of cells occupied by the guardian's sprite
91FE | INC HL
91FF | LD (HL),C
9200 | ADD HL,DE
9201 | LD (HL),C
9202 | INC HL
9203 | LD (HL),C
9204 | LD A,(IX+$03) | Pick up the fourth byte of the guardian's buffer
9207 | AND $0E | Does the guardian's sprite occupy only two rows of cells at the moment?
9209 | JR Z,$920F | Jump if so
920B | ADD HL,DE | Set the attribute bytes in the buffer at 5C00 for the third row of cells occupied by the guardian's sprite
920C | LD (HL),C
920D | INC HL
920E | LD (HL),C
920F | LD C,$01 | Prepare C for the call to 9456 later on
9211 | LD A,(IX+$01) | Now bits 5-7 of A hold the animation frame mask
9214 | AND (IX+$00) | 'AND' on the current animation frame (bits 5-7)
9217 | OR (IX+$02) | 'OR' on the base sprite index (bits 5-7)
921A | AND $E0 | Keep only bits 5-7
921C | LD E,A | Point DE at the graphic data for the guardian's current animation frame (see AB00)
921D | LD D,(IX+$05)
9220 | LD H,$82 | Point HL at the guardian's current location in the screen buffer at 6000
9222 | LD L,(IX+$03)
9225 | LD A,(IX+$02)
9228 | AND $1F
922A | OR (HL)
922B | INC HL
922C | LD H,(HL)
922D | LD L,A
922E | CALL $9456 | Draw the guardian
9231 | JP NZ,$90B7 | Kill Willy if the guardian collided with him
9234 | JP $93B3 | Jump to consider the next entity
We are dealing with an arrow. Your browser doesn't support HTML5 audio. Here is a link to the audio instead.
9237 | BIT 7,(IX+$00) | Is the arrow travelling left to right?
923B | JR NZ,$9244 | Jump if so
923D | DEC (IX+$04) | Decrement the arrow's x-coordinate
9240 | LD C,$2C | The sound effect for an arrow travelling right to left is made when the x-coordinate is 44
9242 | JR $9249 |
9244 | INC (IX+$04) | Increment the arrow's x-coordinate
9247 | LD C,$F4 | The sound effect for an arrow travelling left to right is made when the x-coordinate is 244
9249 | LD A,(IX+$04) | Pick up the arrow's x-coordinate (0-255)
924C | CP C | Is it time to make the arrow sound effect?
924D | JR NZ,$9262 | Jump if not
924F | LD BC,$0280 | Prepare the delay counters (B=0x02, C=0x80) for the arrow sound effect
9252 | LD A,($80DE) | Pick up the border colour for the current room from 80DE
9255 | OUT ($FE),A | Produce the arrow sound effect
9257 | XOR $18
9259 | DJNZ $9259
925B | LD B,C
925C | DEC C
925D | JR NZ,$9255
925F | JP $93B3 | Jump to consider the next entity
9262 | AND $E0 | Is the arrow's x-coordinate in the range 0-31 (i.e. on-screen)?
9264 | JP NZ,$93B3 | If not, jump to consider the next entity
9267 | LD E,(IX+$02) | Point DE at the entry in the screen buffer address lookup table at 8200 that corresponds to the arrow's y-coordinate
926A | LD D,$82
926C | LD A,(DE) | Pick up the LSB of the screen buffer address
926D | ADD A,(IX+$04) | Adjust it for the arrow's x-coordinate
9270 | LD L,A | Point HL at the arrow's current location in the attribute buffer at 5C00
9271 | LD A,E
9272 | AND $80
9274 | RLCA
9275 | OR $5C
9277 | LD H,A
9278 | LD (IX+$05),$00 | Initialise the collision detection byte (0x00=off, 0xFF=on)
927C | LD A,(HL) | Pick up the room attribute byte at the arrow's location
927D | AND $07 | Keep only bits 0-2 (INK colour)
927F | CP $07 | Is the INK white?
9281 | JR NZ,$9286 | Jump if not
9283 | DEC (IX+$05) | Activate collision detection
9286 | LD A,(HL) | Set the INK colour to white at the arrow's location
9287 | OR $07
9289 | LD (HL),A
928A | INC DE | Pick up the MSB of the screen buffer address for the arrow's location
928B | LD A,(DE)
928C | LD H,A | Point HL at the top pixel row of the arrow's location in the screen buffer at 6000
928D | DEC H
928E | LD A,(IX+$06) | Draw the top pixel row of the arrow
9291 | LD (HL),A
9292 | INC H | Point HL at the middle pixel row of the arrow's location in the screen buffer at 6000
9293 | LD A,(HL) | Pick up the graphic byte that's already here
9294 | AND (IX+$05) | Has the arrow hit anything that has white INK (e.g. Willy)?
9297 | JP NZ,$90B7 | If so, kill Willy
929A | LD (HL),$FF | Draw the shaft of the arrow
929C | INC H | Point HL at the bottom pixel row of the arrow's location in the screen buffer at 6000
929D | LD A,(IX+$06) | Draw the bottom pixel row of the arrow
92A0 | LD (HL),A
92A1 | JP $93B3 | Jump to consider the next entity
We are dealing with a rope.
92A4 | LD IY,$8200 | Point IY at the first byte of the screen buffer address lookup table at 8200
92A8 | LD (IX+$09),$00 | Initialise the second byte in the following entity buffer to zero; this will count the segments of rope to draw
92AC | LD A,(IX+$02) | Initialise the fourth byte of the rope's buffer; this holds the x-coordinate of the cell in which the segment of rope under consideration will be drawn
92AF | LD (IX+$03),A
92B2 | LD (IX+$05),$80 | Initialise the sixth byte of the rope's buffer to 0x80 (bit 7 set); the value held here is used to draw the segment of rope under consideration
The following loop draws each segment of the rope from top to bottom.
92B6 | LD A,(IY+$00) | Point HL at the location of the segment of rope under consideration in the screen buffer at 6000
92B9 | ADD A,(IX+$03)
92BC | LD L,A
92BD | LD H,(IY+$01)
92C0 | LD A,($85D6) | Pick up the rope status indicator at 85D6
92C3 | OR A | Is Willy on the rope, or has he recently jumped or dropped off it?
92C4 | JR NZ,$92D6 | Jump if so
92C6 | LD A,(IX+$05) | Pick up the drawing byte
92C9 | AND (HL) | Is this segment of rope touching anything else that's been drawn so far (e.g. Willy)?
92CA | JR Z,$930E | Jump if not
92CC | LD A,(IX+$09) | Copy the segment counter into the rope status indicator at 85D6
92CF | LD ($85D6),A
92D2 | SET 0,(IX+$0B) | Signal: Willy is on the rope
92D6 | CP (IX+$09) | Does the rope status indicator at 85D6 match the segment counter?
92D9 | JR NZ,$930E | Jump if not
92DB | BIT 0,(IX+$0B) | Is Willy on the rope (and clinging to this particular segment)?
92DF | JR Z,$930E | Jump if not
92E1 | LD B,(IX+$03) | Copy the x-coordinate of the cell containing the segment of rope under consideration to B
92E4 | LD A,(IX+$05) | Pick up the drawing byte in A
92E7 | LD C,$01 | The value in C will specify Willy's next animation frame; initialise it to 1
92E9 | CP $04 | Is the set bit of the drawing byte in bit 0 or 1?
92EB | JR C,$92FC | Jump if so
92ED | LD C,$00 | Assume that Willy's next animation frame will be 0
92EF | CP $10 | Is the set bit of the drawing byte in bit 2 or 3?
92F1 | JR C,$92FC | Jump if so
92F3 | DEC B | Decrement the x-coordinate
92F4 | LD C,$03 | Assume that Willy's next animation frame will be 3
92F6 | CP $40 | Is the set bit of the drawing byte in bit 4 or 5?
92F8 | JR C,$92FC | Jump if so
92FA | LD C,$02 | Willy's next animation frame will be 2 (the set bit of the drawing byte is in bit 6 or 7)
92FC | LD ($85D2),BC | Set Willy's animation frame at 85D2, and temporarily store his x-coordinate at 85D3
9300 | LD A,IYl | Update Willy's y-coordinate at 85CF to account for his change of location as the rope moves
9302 | SUB $10
9304 | LD ($85CF),A
9307 | PUSH HL | Save HL briefly
9308 | CALL $8E9C | Update Willy's attribute buffer address at 85D3 to account for his change of location as the rope moves
930B | POP HL | Restore the screen buffer address of the segment of rope under consideration to HL
930C | JR $930E | Make a redundant jump to the next instruction
930E | LD A,(IX+$05) | Draw a pixel of the rope to the screen buffer at 6000
9311 | OR (HL)
9312 | LD (HL),A
9313 | LD A,(IX+$09) | Point HL at the relevant entry in the second half of the rope animation table at 8300
9316 | ADD A,(IX+$01)
9319 | LD L,A
931A | SET 7,L
931C | LD H,$83
931E | LD E,(HL) | Add its value to IY; now IY points at the entry in the screen buffer address lookup table at 8200 that corresponds to the next segment of rope to consider
931F | LD D,$00
9321 | ADD IY,DE
9323 | RES 7,L | Point HL at the relevant entry in the first half of the rope animation table at 8300
9325 | LD A,(HL) | Pick up its value
9326 | OR A | Is it zero?
9327 | JR Z,$9350 | Jump if so
9329 | LD B,A | Copy the rope animation table entry value to B; this will count the rotations of the drawing byte
932A | BIT 7,(IX+$01) | Is the rope currently right of centre?
932E | JR Z,$9341 | Jump if so
9330 | RLC (IX+$05) | Rotate the drawing byte left once
9334 | BIT 0,(IX+$05) | Did that push the set bit from bit 7 into bit 0?
9338 | JR Z,$933D | Jump if not
933A | DEC (IX+$03) | Decrement the x-coordinate for the cell containing this segment of rope
933D | DJNZ $9330 | Jump back until the drawing byte has been rotated as required
933F | JR $9350 | Jump to consider the next segment of rope
9341 | RRC (IX+$05) | Rotate the drawing byte right once
9345 | BIT 7,(IX+$05) | Did that push the set bit from bit 0 into bit 7?
9349 | JR Z,$934E | Jump if not
934B | INC (IX+$03) | Increment the x-coordinate for the cell containing this segment of rope
934E | DJNZ $9341 | Jump back until the drawing byte has been rotated as required
9350 | LD A,(IX+$09) | Pick up the segment counter
9353 | CP (IX+$04) | Have we drawn every segment of the rope yet?
9356 | JR Z,$935E | Jump if so
9358 | INC (IX+$09) | Increment the segment counter
935B | JP $92B6 | Jump back to draw the next segment of rope
Now that the entire rope has been drawn, deal with Willy's movement along it.
935E | LD A,($85D6) | Pick up the rope status indicator at 85D6
9361 | BIT 7,A | Has Willy recently jumped off the rope or dropped off the bottom of it (A>=0xF0)?
9363 | JR Z,$936F | Jump if not
9365 | INC A | Update the rope status indicator at 85D6
9366 | LD ($85D6),A
9369 | RES 0,(IX+$0B) | Signal: Willy is not on the rope
936D | JR $93B3 | Jump to consider the next entity
936F | BIT 0,(IX+$0B) | Is Willy on the rope?
9373 | JR Z,$93B3 | If not, jump to consider the next entity
9375 | LD A,($85D0) | Pick up Willy's direction and movement flags from 85D0
9378 | BIT 1,A | Is Willy moving up or down the rope?
937A | JR Z,$93B3 | If not, jump to consider the next entity
937C | RRCA | XOR Willy's direction bit (0=facing right, 1=facing left) with the rope's direction bit (0=swinging right to left, 1=swinging left to right)
937D | XOR (IX+$00)
9380 | RLCA
9381 | RLCA | Now A=1 if Willy is facing the same direction as the rope is swinging (he will move down the rope), or -1 otherwise (he will move up the rope)
9382 | AND $02
9384 | DEC A
9385 | LD HL,$85D6 | Increment or decrement the rope status indicator at 85D6
9388 | ADD A,(HL)
9389 | LD (HL),A
938A | LD A,($80EB) | Pick up the number of the room above from 80EB and copy it to C
938D | LD C,A
938E | LD A,($8420) | Pick up the number of the current room from 8420
9391 | CP C | Is there a room above this one?
9392 | JR NZ,$939B | Jump if so
9394 | LD A,(HL) | Pick up the rope status indicator at 85D6
9395 | CP $0C | Is it 0x0C or greater?
9397 | JR NC,$939B | Jump if so
9399 | LD (HL),$0C | Set the rope status indicator at 85D6 to 0x0C (there is nowhere to go above this rope)
939B | LD A,(HL) | Pick up the rope status indicator at 85D6
939C | CP (IX+$04) | Compare it with the length of the rope
939F | JR C,$93B3 | If Willy is at or above the bottom of the rope, jump to consider the next entity
93A1 | JR Z,$93B3
93A3 | LD (HL),$F0 | Set the rope status indicator at 85D6 to 0xF0 (Willy has just dropped off the bottom of the rope)
93A5 | LD A,($85CF) | Round down Willy's y-coordinate at 85CF to the nearest multiple of 8; this might move him upwards a little, but ensures that his actual pixel y-coordinate is a multiple of 4 before he starts falling
93A8 | AND $F8
93AA | LD ($85CF),A
93AD | XOR A | Initialise the airborne status indicator at 85D1
93AE | LD ($85D1),A
93B1 | JR $93B3 | Make a redundant jump to the next instruction
The current entity has been dealt with. Time for the next one.
93B3 | LD DE,$0008 | Point IX at the first byte of the next entity's buffer
93B6 | ADD IX,DE
93B8 | JP $91C2 | Jump back to deal with it