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 |