![]() |
Routines |
| Prev: E3D6 | Up: Map | Next: E49F |
|
Used by the routine at SORT_AND_DRAW_THINGS.
Called by the depth sort (SORT_AND_DRAW_THINGS) for each object in turn, back to front. The projection (PROJECT_THING) gives the object's place relative to the knight's in DRAW_X and DRAW_Y; adding the drawing offsets (+C, +D) gives the pixel x and y of the sprite's bottom left corner, which are kept in +E and +F. The game's y counts upwards: the play area is 112 lines, from y 72 at the bottom (line 127 of the screen) to 183 (line 16), and its buffer 24 bytes a row from x 16, of which the first two bytes are a margin never shown (COPY_BUFFER).
An object is not drawn at all if its x is below 16 or above 202, or its y is 184 or more, or either high byte from the projection is not 0. If its bottom is below the play area, only its rows from y 72 up are drawn; if its top is above, only those below. The knight's graphics (16 to 47, legs and top) are cut instead at ARRIVING lines above the bottom, which counts up to 112 as he appears at a new life (UPDATE_KNIGHT), so he is shown from the ground up. The entry point DRAW_SPRITE_AT draws at +E and +F as they are, with no projection and no checks at the sides; the ending's pictures use it (ENDING_PIT_FRONT).
The row loop is unrolled for a sprite five bytes wide, twice: a plain run for a sprite whose x is on a byte boundary (SPRITE_ALIGNED_RUN), and a shifted run that reads its bytes through the tables of SHIFT_TABLES and touches one byte more a row (SPRITE_SHIFTED_RUN). This routine patches the offset of the JR in SPRITE_ROW to enter the right run as many units from its end as the sprite is wide, and the operand of the ADD at SPRITE_NEXT_ROW (SPRITE_SHIFTED_FOUR) with the step from the last byte drawn in a row to the first of the row above. Bits 1 and 2 of x choose the shift, 0 (the plain run), 2, 4 or 6 pixels; bit 0 is ignored, so things move across in steps of two pixels. The stack pointer reads the sprite: SP is pointed at the data and each POP DE fetches a mask into E and its image into D, the real SP kept in SAVED_SP meanwhile.
On the way out SPRITE_WIDTH holds the bytes drawn a row (one more than the sprite's width when shifted), SPRITE_ROWS the rows drawn, and bit 1 of the object's flags (+7) is set. Checked in the simulator, drawing a monster's sprite into an empty buffer at a range of places: the rows land from y less 72 up, the clipping at the bottom, the top and ARRIVING comes out as described, and the patched offsets and steps are the ones worked out here.
Nothing is clipped at the sides beyond the tests on x. A sprite starting in a row's last byte runs on into the first bytes of the row above: the two margin bytes hide two of them, but a four-byte sprite drawn shifted there would put its last two into the visible columns 2 and 3 of the row above (the simulator shows the run-on; whether it is ever seen in play is not known).
|
||||||||
| DRAW_SPRITE | E3D9 | CALL PROJECT_THING | Project the object into DRAW_X and DRAW_Y | |||||
| E3DC | LD HL,(DRAW_X) | x = DRAW_X plus the offset +C; not drawn unless DRAW_X's high byte is 0 and x is 16 to 202 | ||||||
| E3DF | LD A,H | |||||||
| E3E0 | AND A | |||||||
| E3E1 | RET NZ | |||||||
| E3E2 | LD A,L | |||||||
| E3E3 | ADD A,(IX+$0C) | |||||||
| E3E6 | CP $CB | |||||||
| E3E8 | RET NC | |||||||
| E3E9 | CP $10 | |||||||
| E3EB | RET C | |||||||
| E3EC | LD (IX+$0E),A | Keep x in +E | ||||||
| E3EF | LD HL,(DRAW_Y) | y = DRAW_Y plus +D; not drawn unless the high byte is 0 and y is below 184 | ||||||
| E3F2 | LD A,H | |||||||
| E3F3 | AND A | |||||||
| E3F4 | RET NZ | |||||||
| E3F5 | LD A,L | |||||||
| E3F6 | ADD A,(IX+$0D) | |||||||
| E3F9 | CP $B8 | |||||||
| E3FB | RET NC | |||||||
| E3FC | LD (IX+$0F),A | Keep y in +F | ||||||
|
This entry point is used by the routine at ENDING_PIT_FRONT.
|
||||||||
| DRAW_SPRITE_AT | E3FF | CALL TURN_SPRITE | DRAW_SPRITE_AT: find the sprite, turned the right way; DE = its width byte | |||||
| E402 | LD A,(IX+$0E) | Bits 1-2 of x: 0 for a sprite on a byte boundary | ||||||
| E405 | AND $06 | |||||||
| E407 | JP Z,DRAW_SPRITE_6 | |||||||
| E40A | OR $F8 | H = the first page of the shift's pair: $FA, $FC or $FE for 2, 4 or 6 pixels | ||||||
| E40C | LD H,A | |||||||
| E40D | LD A,(DE) | B and SPRITE_WIDTH = the width plus one: a shifted row touches one byte more | ||||||
| E40E | INC DE | |||||||
| E40F | AND $07 | |||||||
| E411 | INC A | |||||||
| E412 | LD B,A | |||||||
| E413 | LD (SPRITE_WIDTH),A | |||||||
| E416 | DEC A | The JR offset into the shifted run: 18 bytes a unit, entered as many units from the end as the sprite is wide | ||||||
| E417 | AND $07 | |||||||
| E419 | ADD A,A | |||||||
| E41A | LD C,A | |||||||
| E41B | ADD A,A | |||||||
| E41C | ADD A,A | |||||||
| E41D | ADD A,A | |||||||
| E41E | ADD A,C | |||||||
| E41F | NEG | |||||||
| E421 | ADD A,$5A | |||||||
| DRAW_SPRITE_0 | E423 | LD ($E4CC),A | Patch it into the JR in SPRITE_ROW, for either run | |||||
| E426 | LD A,B | The step from the last byte drawn in a row to the first of the next: 25 less the bytes a row; patched into SPRITE_NEXT_ROW | ||||||
| E427 | CPL | |||||||
| E428 | ADD A,$1A | |||||||
| E42A | LD ($E52A),A | |||||||
| E42D | EX DE,HL | HL = the height byte | ||||||
| E42E | LD A,(IX+$00) | C = how far up from the bottom may be drawn: the whole 112 lines, but ARRIVING for the knight's legs and top (graphics 16 to 47) | ||||||
| E431 | SUB $10 | |||||||
| E433 | CP $20 | |||||||
| E435 | LD A,$70 | |||||||
| E437 | JR NC,DRAW_SPRITE_1 | |||||||
| E439 | LD A,(ARRIVING) | |||||||
| DRAW_SPRITE_1 | E43C | LD C,A | ||||||
| E43D | LD A,(IX+$0F) | y less 72: the lines above the play area's bottom; below it, clip there | ||||||
| E440 | SUB $48 | |||||||
| E442 | JR C,DRAW_SPRITE_4 | |||||||
| E444 | SUB C | Nothing to draw if it starts at or above the limit | ||||||
| E445 | RET NC | |||||||
| E446 | NEG | The rows: the lines up to the limit, or the height if fewer; HL on to the data | ||||||
| E448 | CP (HL) | |||||||
| E449 | JR C,DRAW_SPRITE_2 | |||||||
| E44B | LD A,(HL) | |||||||
| DRAW_SPRITE_2 | E44C | INC HL | ||||||
| E44D | LD (SPRITE_ROWS),A | |||||||
| DRAW_SPRITE_3 | E450 | EX DE,HL | BC = the buffer address of the sprite's bottom left byte (BUFFER_ADDRESS), from +E and +F; HL = the table page again | |||||
| E451 | PUSH HL | |||||||
| E452 | LD L,(IX+$0E) | |||||||
| E455 | LD H,(IX+$0F) | |||||||
| E458 | CALL BUFFER_ADDRESS | |||||||
| E45B | LD C,L | |||||||
| E45C | LD B,H | |||||||
| E45D | POP HL | |||||||
| E45E | LD (SAVED_SP),SP | Keep SP, and point it at the data | ||||||
| E462 | EX DE,HL | |||||||
| E463 | LD SP,HL | |||||||
| E464 | EX DE,HL | |||||||
| E465 | SET 1,(IX+$07) | Mark the object drawn | ||||||
| E469 | LD A,(SPRITE_ROWS) | A = the rows; into the row loop | ||||||
| E46C | JR SPRITE_ROW | |||||||
| DRAW_SPRITE_4 | E46E | NEG | Below the bottom: C = the lines under it; the rows left above it, if any | |||||
| E470 | LD C,A | |||||||
| E471 | LD A,(HL) | |||||||
| E472 | SUB C | |||||||
| E473 | RET M | |||||||
| E474 | RET Z | |||||||
| E475 | LD (SPRITE_ROWS),A | |||||||
| E478 | LD B,$00 | Skip C rows of the data, twice the width a row, and start at the bottom line | ||||||
| E47A | DEC HL | |||||||
| E47B | LD A,(HL) | |||||||
| E47C | AND $3F | |||||||
| E47E | INC HL | |||||||
| E47F | INC HL | |||||||
| E480 | SLA C | |||||||
| E482 | RL B | |||||||
| DRAW_SPRITE_5 | E484 | ADD HL,BC | ||||||
| E485 | DEC A | |||||||
| E486 | JR NZ,DRAW_SPRITE_5 | |||||||
| E488 | LD (IX+$0F),$48 | |||||||
| E48C | JR DRAW_SPRITE_3 | Draw | ||||||
| DRAW_SPRITE_6 | E48E | LD A,(DE) | On a byte boundary: B and SPRITE_WIDTH = the width | |||||
| E48F | INC DE | |||||||
| E490 | AND $0F | |||||||
| E492 | LD (SPRITE_WIDTH),A | |||||||
| E495 | LD B,A | |||||||
| E496 | ADD A,A | The JR offset into the plain run: 8 bytes a unit, entered as many units from the end as the sprite is wide | ||||||
| E497 | ADD A,A | |||||||
| E498 | ADD A,A | |||||||
| E499 | NEG | |||||||
| E49B | SUB $06 | |||||||
| E49D | JR DRAW_SPRITE_0 | |||||||
| Prev: E3D6 | Up: Map | Next: E49F |