Prev: AF8F Up: Map Next: B107
AFDF: Collision
This handles collisions, including items being pushed around.
Used by the routines at touch and spawn_character.
Output
F Z/NZ => no collision/collision.
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