![]() |
Routines |
| Prev: AF8F | Up: Map | Next: B107 |
|
This handles collisions, including items being pushed around.
Used by the routines at touch and spawn_character.
|
||||||||
|
Iterate over characters being collided with (e.g. stove).
|
||||||||
| collision | AFDF | LD HL,$8001 | Point HL at the first vischar's flags field | |||||
| AFE2 | LD B,$08 | Set B for eight iterations | ||||||
|
Start loop
|
||||||||
| collision_0 | AFE4 | BIT 7,(HL) | Is the vischar_FLAGS_NO_COLLIDE flag bit set? | |||||
| AFE6 | JP NZ,collision_18 | Skip if so | ||||||
| AFE9 | PUSH BC | Preserve the loop counter | ||||||
| AFEA | PUSH HL | Preserve the vischar pointer | ||||||
|
Test for contact between the current vischar and saved_pos.
|
||||||||
| AFEB | LD A,$0E | Point HL at vischar's X position | ||||||
| AFED | ADD A,L | |||||||
| AFEE | LD L,A | |||||||
|
Check X is within (-4..+4)
|
||||||||
| AFEF | LD C,(HL) | Fetch X position | ||||||
| AFF0 | INC L | |||||||
| AFF1 | LD B,(HL) | |||||||
| AFF2 | EX DE,HL | Save our vischar pointer while we compare bounds | ||||||
| AFF3 | LD HL,($81A4) | Fetch saved_pos_x | ||||||
| AFF6 | LD A,$04 | Add 4 to the X position - our upper bound | ||||||
| AFF8 | ADD A,C | |||||||
| AFF9 | LD C,A | |||||||
| AFFA | JR NC,collision_1 | |||||||
| AFFC | INC B | |||||||
| AFFD | AND A | Clear the carry flag | ||||||
| collision_1 | AFFE | SBC HL,BC | Compare saved_pos_x to (X position + 4) | |||||
| B000 | JR Z,collision_3 | Equal - jump forward to comparing Y position | ||||||
| B002 | JP NC,collision_pop_next | If (saved_pos_x >= (X position + 4)) there was no collision, so jump to the next iteration | ||||||
| B005 | SUB $08 | Reduce A by 8 giving (X position - 4) - our lower bound | ||||||
| B007 | LD C,A | |||||||
| B008 | JR NC,collision_2 | |||||||
| B00A | DEC B | |||||||
| B00B | AND A | |||||||
| collision_2 | B00C | LD HL,($81A4) | Fetch saved_pos_x again | |||||
| B00F | SBC HL,BC | Compare saved_pos_x to (X position - 4) | ||||||
| B011 | JP C,collision_pop_next | If (saved_pos_x < (X position - 4)) there was no collision, so jump to the next iteration | ||||||
| collision_3 | B014 | EX DE,HL | Restore our vischar pointer | |||||
| B015 | INC L | Advance to Y position | ||||||
|
Check Y is within (-4..+4)
|
||||||||
| B016 | LD C,(HL) | Fetch Y position | ||||||
| B017 | INC L | |||||||
| B018 | LD B,(HL) | |||||||
| B019 | EX DE,HL | Save our vischar pointer while we compare bounds | ||||||
| B01A | LD HL,($81A6) | Fetch saved_pos_y | ||||||
| B01D | LD A,$04 | Add 4 to the Y position - our upper bound | ||||||
| B01F | ADD A,C | |||||||
| B020 | LD C,A | |||||||
| B021 | JR NC,collision_4 | |||||||
| B023 | INC B | |||||||
| B024 | AND A | Clear the carry flag | ||||||
| collision_4 | B025 | SBC HL,BC | Compare saved_pos_y to (Y position + 4) | |||||
| B027 | JR Z,collision_6 | Equal - jump forward to comparing height | ||||||
| B029 | JP NC,collision_pop_next | If (saved_pos_y >= (Y position + 4)) there was no collision, so jump to the next iteration | ||||||
| B02C | SUB $08 | Reduce A by 8 giving (Y position - 4) - our lower bound | ||||||
| B02E | LD C,A | |||||||
| B02F | JR NC,collision_5 | |||||||
| B031 | DEC B | |||||||
| B032 | AND A | |||||||
| collision_5 | B033 | LD HL,($81A6) | Fetch saved_pos_y again | |||||
| B036 | SBC HL,BC | Compare saved_pos_y to (Y position - 4) | ||||||
| B038 | JP C,collision_pop_next | If (saved_pos_y < (Y position - 4)) there was no collision, so jump to the next iteration | ||||||
| collision_6 | B03B | EX DE,HL | Restore our vischar pointer | |||||
| B03C | INC L | Advance to height | ||||||
|
Ensure that the heights are within 24 of each other. This will stop the character colliding with any guards high up in watchtowers.
|
||||||||
| B03D | LD C,(HL) | Fetch height | ||||||
| B03E | LD A,($81A8) | Fetch saved_height | ||||||
| B041 | SUB C | Subtract height from saved_height | ||||||
| B042 | JR NC,collision_7 | If negative flip the sign - get the absolute value | ||||||
| B044 | NEG | |||||||
| collision_7 | B046 | CP $18 | If the result is >= 24 then jump to the next iteration | |||||
| B048 | JP NC,collision_pop_next | |||||||
|
Check for pursuit.
|
||||||||
| B04B | LD A,(IY+$01) | Read the vischar's flags | ||||||
| B04E | AND $0F | AND the flags with vischar_FLAGS_PURSUIT_MASK | ||||||
| B050 | CP $01 | Is the result vischar_PURSUIT_PURSUE? | ||||||
| B052 | JR NZ,collision_9 | If not, jump forward to collision checking | ||||||
|
Vischar (IY) is pursuing.
|
||||||||
| B054 | POP HL | Restore vischar pointer | ||||||
| B055 | PUSH HL | |||||||
| B056 | DEC L | Point at vischar base, not flags | ||||||
| B057 | LD A,L | Is the current vischar the hero's? ($8000) | ||||||
| B058 | AND A | |||||||
| B059 | JR NZ,collision_9 | |||||||
|
Currently tested vischar (HL) is the hero's.
|
||||||||
| B05B | LD A,($AF8E) | Fetch global bribed character | ||||||
| B05E | CP (IY+$00) | Does it match IY's vischar character? | ||||||
| B061 | JR NZ,collision_8 | No, jump forward to solitary check | ||||||
|
Vischar IY is a bribed character pursuing the hero.
When the pursuer catches the hero the bribe will be accepted.
|
||||||||
| B063 | CALL accept_bribe | Call accept_bribe | ||||||
| B066 | JR collision_9 | (else) | ||||||
|
Vischar IY is a hostile who's caught the hero!
|
||||||||
| collision_8 | B068 | POP HL | Restore vischar pointer | |||||
| B069 | POP BC | Restore loop counter | ||||||
| B06A | PUSH IY | Unused sequence: HL = IY + 1 | ||||||
| B06C | POP HL | |||||||
| B06D | INC L | |||||||
| B06E | JP solitary | Exit via solitary | ||||||
|
Check for collisions with items.
|
||||||||
| collision_9 | B071 | POP HL | Restore vischar pointer | |||||
| B072 | DEC L | Point at vischar base, not flags | ||||||
| B073 | LD A,(HL) | Fetch the vischar's character | ||||||
| B074 | CP $1A | Is the character >= character_26_STOVE_1? | ||||||
| B076 | JR C,collision_16 | Jump if NOT | ||||||
|
It's an item.
|
||||||||
| B078 | PUSH HL | Preserve the vischar pointer | ||||||
| B079 | EX AF,AF' | Bank the character index | ||||||
| B07A | LD A,$11 | Point HL at vischar->mi.pos.y | ||||||
| B07C | ADD A,L | |||||||
| B07D | LD L,A | |||||||
| B07E | EX AF,AF' | Retrieve the character index | ||||||
|
By default, setup for the stove. It can move on the Y axis only (bottom left to top right).
|
||||||||
| B07F | LD BC,$0723 | Set B to 7 - the permitted range, in either direction, from the centre point and set C to 35 - the centre point | ||||||
| B082 | CP $1C | Compare character index with character_28_CRATE | ||||||
| B084 | LD A,(IY+$0E) | (interleaved) Fetch IY's direction | ||||||
| B087 | JR NZ,collision_10 | If it's not the crate then jump to the stove handling | ||||||
|
Handle the crate. It can move on the X axis only (top left to bottom right).
|
||||||||
| B089 | DEC L | Point HL at vischar->mi.pos.x | ||||||
| B08A | DEC L | |||||||
| B08B | LD C,$36 | Centre point is 54 (crate will move 47..54..61) | ||||||
| B08D | XOR $01 | Swap axis left<=>right | ||||||
|
Top left case.
|
||||||||
| collision_10 | B08F | AND A | Test the direction: Is it top left? (zero) | |||||
| B090 | JR NZ,collision_12 | Jump forward to next check if not | ||||||
|
The player is pushing the movable item from its front, so centre it.
|
||||||||
| B092 | LD A,(HL) | Load the coordinate | ||||||
| B093 | CP C | Is it already at the centre point? | ||||||
| B094 | JR Z,collision_15 | Jump forward if so | ||||||
| B096 | JR C,collision_11 | If the coordinate is larger than the centre point then decrement, else increment its position | ||||||
| B098 | DEC (HL) | |||||||
| B099 | DEC (HL) | |||||||
| collision_11 | B09A | INC (HL) | ||||||
| B09B | JR collision_15 | (else) | ||||||
|
Top right case.
|
||||||||
| collision_12 | B09D | CP $01 | Test the direction: Is it top right? (one) | |||||
| B09F | JR NZ,collision_13 | Jump forward to next check if not | ||||||
| B0A1 | LD A,C | If the coordinate is not at its maximum (C+B) then increment its position | ||||||
| B0A2 | ADD A,B | |||||||
| B0A3 | CP (HL) | |||||||
| B0A4 | JR Z,collision_15 | |||||||
| B0A6 | INC (HL) | |||||||
| B0A7 | JR collision_15 | (else) | ||||||
|
Bottom right case.
|
||||||||
| collision_13 | B0A9 | CP $02 | Test the direction: Is it bottom right? (two) | |||||
| B0AB | JR NZ,collision_14 | Jump forward to next check if not | ||||||
| B0AD | LD A,C | Set the position to minimum (C-B) irrespective. Note that this never seems to happen in practice in the game | ||||||
| B0AE | SUB B | |||||||
| B0AF | LD (HL),A | |||||||
| B0B0 | JR collision_15 | (else) | ||||||
|
Bottom left case.
|
||||||||
| collision_14 | B0B2 | LD A,C | If the coordinate is not at its minimum (C-B) then decrement its position | |||||
| B0B3 | SUB B | |||||||
| B0B4 | CP (HL) | |||||||
| B0B5 | JR Z,collision_15 | |||||||
| B0B7 | DEC (HL) | |||||||
| collision_15 | B0B8 | POP HL | Restore the vischar pointer | |||||
| collision_16 | B0B9 | POP BC | Restore the loop counter | |||||
|
Check for collisions with characters.
|
||||||||
| B0BA | LD A,L | Point at vischar input field | ||||||
| B0BB | ADD A,$0D | |||||||
| B0BD | LD L,A | |||||||
| B0BE | LD A,(HL) | Load the input field and mask off the input_KICK flag | ||||||
| B0BF | AND $7F | |||||||
| B0C1 | JR Z,collided_facing | Jump forward if the input field is zero | ||||||
| B0C3 | INC L | Point at the direction field | ||||||
| B0C4 | LD A,(HL) | Swap direction top <=> bottom | ||||||
| B0C5 | XOR $02 | |||||||
| B0C7 | CP (IY+$0E) | If direction != state->IY->direction | ||||||
| B0CA | JR Z,collided_facing | |||||||
| collided_not_facing | B0CC | LD (IY+$0D),$80 | Set IY's input to input_KICK | |||||
|
Delay calling character_behaviour for five turns. This delay controls how long it takes before a blocked character will try another direction.
|
||||||||
| collided_set_delay | B0D0 | LD A,(IY+$07) | IY->counter_and_flags = (IY->counter_and_flags & ~vischar_BYTE7_COUNTER_MASK) | 5 | |||||
| B0D3 | AND $F0 | |||||||
| B0D5 | OR $05 | |||||||
| B0D7 | LD (IY+$07),A | |||||||
|
Note: The following return does work but it's odd that it's conditional.
|
||||||||
| B0DA | RET NZ | Return | ||||||
|
Note: The C direction field ought to be masked so that we don't access out-of-bounds in new_inputs[] if we collide when crawling.
|
||||||||
| collided_facing | B0DB | LD C,(IY+$0E) | Fetch IY->direction, widening it to BC | |||||
| B0DE | LD B,$00 | |||||||
| B0E0 | LD HL,$B0F8 | Point HL at collision_new_inputs | ||||||
| B0E3 | ADD HL,BC | Index it by direction (in BC) | ||||||
| B0E4 | LD A,(HL) | Fetch the direction | ||||||
| B0E5 | LD (IY+$0D),A | IY->input = direction | ||||||
| B0E8 | BIT 0,C | Is the new direction TR or BL? | ||||||
| B0EA | JR NZ,collision_17 | Jump if so | ||||||
| B0EC | RES 5,(IY+$07) | IY->counter_and_flags &= ~vischar_BYTE7_Y_DOMINANT | ||||||
| B0F0 | JR collided_set_delay | Jump to 'collided_set_delay' | ||||||
| collision_17 | B0F2 | SET 5,(IY+$07) | IY->counter_and_flags |= vischar_BYTE7_Y_DOMINAN | |||||
| B0F6 | JR collided_set_delay | Jump to 'collided_set_delay' | ||||||
|
Inputs which move the character in the next anticlockwise direction.
|
||||||||
| collision_new_inputs | B0F8 | DEFB $85 | = input_(DOWN+LEFT +KICK) => if facing TL, move D+L | |||||
| B0F9 | DEFB $84 | = input_(UP +LEFT +KICK) => if facing TR, move U+L | ||||||
| B0FA | DEFB $87 | = input_(UP +RIGHT+KICK) => if facing BR, move U+R | ||||||
| B0FB | DEFB $88 | = input_(DOWN+RIGHT+KICK) => if facing BL, move D+R | ||||||
| collision_pop_next | B0FC | POP HL | Restore the vischar pointer | |||||
| B0FD | POP BC | Restore the loop counter | ||||||
| collision_18 | B0FE | LD A,L | Step HL to the next vischar | |||||
| B0FF | ADD A,$20 | |||||||
| B101 | LD L,A | |||||||
| B102 | DEC B | ...loop for each vischar | ||||||
| B103 | JP NZ,collision_0 | |||||||
| B106 | RET | Return with Z set | ||||||
| Prev: AF8F | Up: Map | Next: B107 |