shithub: pokecrystal

ref: c5f16c86c80b1b486c534ec855e46d455721c813
dir: /engine/overworld/npc_movement.asm/

View raw version
CanObjectMoveInDirection:
	ld hl, OBJECT_PALETTE
	add hl, bc
	bit SWIMMING_F, [hl]
	jr z, .not_swimming

; BUG: Swimming NPCs aren't limited by their movement radius (see docs/bugs_and_glitches.md)
	ld hl, OBJECT_FLAGS1
	add hl, bc
	bit NOCLIP_TILES_F, [hl]
	push hl
	push bc
	call WillObjectBumpIntoLand
	pop bc
	pop hl
	ret c
	jr .continue

.not_swimming
	ld hl, OBJECT_FLAGS1
	add hl, bc
	bit NOCLIP_TILES_F, [hl]
	jr nz, .noclip_tiles
	push hl
	push bc
	call WillObjectBumpIntoWater
	pop bc
	pop hl
	ret c

.noclip_tiles
.continue
	bit NOCLIP_OBJS_F, [hl]
	jr nz, .noclip_objs

	push hl
	push bc
	call WillObjectBumpIntoSomeoneElse
	pop bc
	pop hl
	ret c

.noclip_objs
	bit MOVE_ANYWHERE_F, [hl]
	jr nz, .move_anywhere
	push hl
	call HasObjectReachedMovementLimit
	pop hl
	ret c

	push hl
	call IsObjectMovingOffEdgeOfScreen
	pop hl
	ret c

.move_anywhere
	and a
	ret

WillObjectBumpIntoWater:
	call CanObjectLeaveTile
	ret c
	ld hl, OBJECT_MAP_X
	add hl, bc
	ld d, [hl]
	ld hl, OBJECT_MAP_Y
	add hl, bc
	ld e, [hl]
	ld hl, OBJECT_PALETTE
	add hl, bc
	bit OAM_PRIORITY, [hl]
	jp nz, WillObjectRemainOnWater
	ld hl, OBJECT_TILE
	add hl, bc
	ld a, [hl]
	ld d, a
	call GetTileCollision
	and a ; LAND_TILE
	jr z, WillObjectBumpIntoTile
	scf
	ret

WillObjectBumpIntoLand:
	call CanObjectLeaveTile
	ret c
	ld hl, OBJECT_TILE
	add hl, bc
	ld a, [hl]
	call GetTileCollision
	cp WATER_TILE
	jr z, WillObjectBumpIntoTile
	scf
	ret

WillObjectBumpIntoTile:
	ld hl, OBJECT_TILE
	add hl, bc
	ld a, [hl]
	call GetSideWallDirectionMask
	ret nc
	push af
	ld hl, OBJECT_WALKING
	add hl, bc
	ld a, [hl]
	maskbits NUM_DIRECTIONS
	ld e, a
	ld d, 0
	ld hl, .dir_masks
	add hl, de
	pop af
	and [hl]
	ret z
	scf
	ret

.dir_masks
	db DOWN_MASK  ; DOWN
	db UP_MASK    ; UP
	db RIGHT_MASK ; LEFT
	db LEFT_MASK  ; RIGHT

CanObjectLeaveTile:
	ld hl, OBJECT_LAST_TILE
	add hl, bc
	ld a, [hl]
	call GetSideWallDirectionMask
	ret nc
	push af
	ld hl, OBJECT_WALKING
	add hl, bc
	maskbits NUM_DIRECTIONS
	ld e, a
	ld d, 0
	ld hl, .dir_masks
	add hl, de
	pop af
	and [hl]
	ret z
	scf
	ret

.dir_masks
	db UP_MASK    ; DOWN
	db DOWN_MASK  ; UP
	db LEFT_MASK  ; LEFT
	db RIGHT_MASK ; RIGHT

GetSideWallDirectionMask:
	ld d, a
	and $f0
	cp HI_NYBBLE_SIDE_WALLS
	jr z, .continue
	cp HI_NYBBLE_SIDE_BUOYS
	jr z, .continue
	xor a
	ret

.continue
	ld a, d
	and $7
	ld e, a
	ld d, 0
	ld hl, .side_wall_masks
	add hl, de
	ld a, [hl]
	scf
	ret

.side_wall_masks
	db RIGHT_MASK             ; COLL_RIGHT_WALL/BUOY
	db LEFT_MASK              ; COLL_LEFT_WALL/BUOY
	db DOWN_MASK              ; COLL_UP_WALL/BUOY
	db UP_MASK                ; COLL_DOWN_WALL/BUOY
	db UP_MASK | RIGHT_MASK   ; COLL_DOWN_RIGHT_WALL/BUOY
	db UP_MASK | LEFT_MASK    ; COLL_DOWN_LEFT_WALL/BUOY
	db DOWN_MASK | RIGHT_MASK ; COLL_UP_RIGHT_WALL/BUOY
	db DOWN_MASK | LEFT_MASK  ; COLL_UP_LEFT_WALL/BUOY

WillObjectRemainOnWater:
	ld hl, OBJECT_WALKING
	add hl, bc
	ld a, [hl]
	maskbits NUM_DIRECTIONS
	jr z, .down
	dec a
	jr z, .up
	dec a
	jr z, .left
	jr .right

.down
	inc e
	push de
	inc d
	jr .continue

.up
	push de
	inc d
	jr .continue

.left
	push de
	inc e
	jr .continue

.right
	inc d
	push de
	inc e

.continue
	call GetCoordTile
	call GetTileCollision
	pop de
	and a ; LAND_TILE
	jr nz, .not_land
	call GetCoordTile
	call GetTileCollision
	and a ; LAND_TILE
	jr nz, .not_land
	xor a
	ret

.not_land
	scf
	ret

CheckFacingObject::
	call GetFacingTileCoord

; Double the distance for counter tiles.
	call CheckCounterTile
	jr nz, .not_counter

	ld a, [wPlayerMapX]
	sub d
	cpl
	inc a
	add d
	ld d, a

	ld a, [wPlayerMapY]
	sub e
	cpl
	inc a
	add e
	ld e, a

.not_counter
	ld bc, wObjectStructs ; redundant
	ld a, 0
	ldh [hMapObjectIndex], a
	call IsNPCAtCoord
	ret nc
	ld hl, OBJECT_WALKING
	add hl, bc
	ld a, [hl]
	cp STANDING
	jr z, .standing
	xor a
	ret

.standing
	scf
	ret

WillObjectBumpIntoSomeoneElse:
	ld hl, OBJECT_MAP_X
	add hl, bc
	ld d, [hl]
	ld hl, OBJECT_MAP_Y
	add hl, bc
	ld e, [hl]
	jr IsNPCAtCoord

IsObjectFacingSomeoneElse: ; unreferenced
	ldh a, [hMapObjectIndex]
	call GetObjectStruct
	call .GetFacingCoords
	call IsNPCAtCoord
	ret

.GetFacingCoords:
	ld hl, OBJECT_MAP_X
	add hl, bc
	ld d, [hl]
	ld hl, OBJECT_MAP_Y
	add hl, bc
	ld e, [hl]
	call GetSpriteDirection
	and a ; OW_DOWN?
	jr z, .down
	cp OW_UP
	jr z, .up
	cp OW_LEFT
	jr z, .left
	; OW_RIGHT
	inc d
	ret

.down
	inc e
	ret

.up
	dec e
	ret

.left
	dec d
	ret

IsNPCAtCoord:
	ld bc, wObjectStructs
	xor a
.loop
	ldh [hObjectStructIndex], a
	call DoesObjectHaveASprite
	jr z, .next

	ld hl, OBJECT_FLAGS1
	add hl, bc
	bit 7, [hl]
	jr nz, .next

	ld hl, OBJECT_PALETTE
	add hl, bc
	bit BIG_OBJECT_F, [hl]
	jr z, .not_big
	call WillObjectIntersectBigObject
	jr nc, .check_current_coords
	jr .continue

.not_big
	ld hl, OBJECT_MAP_X
	add hl, bc
	ld a, [hl]
	cp d
	jr nz, .check_current_coords
	ld hl, OBJECT_MAP_Y
	add hl, bc
	ld a, [hl]
	cp e
	jr nz, .check_current_coords

.continue
	ldh a, [hMapObjectIndex]
	ld l, a
	ldh a, [hObjectStructIndex]
	cp l
	jr nz, .yes

.check_current_coords
	ld hl, OBJECT_LAST_MAP_X
	add hl, bc
	ld a, [hl]
	cp d
	jr nz, .next
	ld hl, OBJECT_LAST_MAP_Y
	add hl, bc
	ld a, [hl]
	cp e
	jr nz, .next
	ldh a, [hMapObjectIndex]
	ld l, a
	ldh a, [hObjectStructIndex]
	cp l
	jr nz, .yes

.next
	ld hl, OBJECT_LENGTH
	add hl, bc
	ld b, h
	ld c, l
	ldh a, [hObjectStructIndex]
	inc a
	cp NUM_OBJECT_STRUCTS
	jr nz, .loop
	and a
	ret

.yes
	scf
	ret

HasObjectReachedMovementLimit:
	ld hl, OBJECT_RADIUS
	add hl, bc
	ld a, [hl]
	and a
	jr z, .nope
	and $f
	jr z, .check_y
	ld e, a
	ld d, a
	ld hl, OBJECT_INIT_X
	add hl, bc
	ld a, [hl]
	sub d
	ld d, a
	ld a, [hl]
	add e
	ld e, a
	ld hl, OBJECT_MAP_X
	add hl, bc
	ld a, [hl]
	cp d
	jr z, .yes
	cp e
	jr z, .yes

.check_y
	ld hl, OBJECT_RADIUS
	add hl, bc
	ld a, [hl]
	swap a
	and $f
	jr z, .nope
	ld e, a
	ld d, a
	ld hl, OBJECT_INIT_Y
	add hl, bc
	ld a, [hl]
	sub d
	ld d, a
	ld a, [hl]
	add e
	ld e, a
	ld hl, OBJECT_MAP_Y
	add hl, bc
	ld a, [hl]
	cp d
	jr z, .yes
	cp e
	jr z, .yes

.nope
	xor a
	ret

.yes
	scf
	ret

IsObjectMovingOffEdgeOfScreen:
	ld hl, OBJECT_MAP_X
	add hl, bc
	ld a, [wXCoord]
	cp [hl]
	jr z, .check_y
	jr nc, .yes
	add $9
	cp [hl]
	jr c, .yes

.check_y
	ld hl, OBJECT_MAP_Y
	add hl, bc
	ld a, [wYCoord]
	cp [hl]
	jr z, .nope
	jr nc, .yes
	add $8
	cp [hl]
	jr c, .yes

.nope
	and a
	ret

.yes
	scf
	ret

IsNPCAtPlayerCoord: ; unreferenced
	ld a, [wPlayerMapX]
	ld d, a
	ld a, [wPlayerMapY]
	ld e, a
	ld bc, wObjectStructs
	xor a
.loop
	ldh [hObjectStructIndex], a
	call DoesObjectHaveASprite
	jr z, .next

	ld hl, OBJECT_MOVEMENT_TYPE
	add hl, bc
	ld a, [hl]
	cp SPRITEMOVEDATA_BIGDOLLSYM
	jr nz, .not_big
	call WillObjectIntersectBigObject
	jr c, .yes
	jr .next

.not_big
	ld hl, OBJECT_MAP_Y
	add hl, bc
	ld a, [hl]
	cp e
	jr nz, .check_current_coords
	ld hl, OBJECT_MAP_X
	add hl, bc
	ld a, [hl]
	cp d
	jr nz, .check_current_coords
	ldh a, [hObjectStructIndex]
	cp PLAYER_OBJECT
	jr z, .next
	jr .yes

.check_current_coords
	ld hl, OBJECT_LAST_MAP_Y
	add hl, bc
	ld a, [hl]
	cp e
	jr nz, .next
	ld hl, OBJECT_LAST_MAP_X
	add hl, bc
	ld a, [hl]
	cp d
	jr nz, .next
	jr .yes

.next
	ld hl, OBJECT_LENGTH
	add hl, bc
	ld b, h
	ld c, l
	ldh a, [hObjectStructIndex]
	inc a
	cp NUM_OBJECT_STRUCTS
	jr nz, .loop
	xor a
	ret

.yes
	scf
	ret

WillObjectIntersectBigObject:
	ld hl, OBJECT_MAP_X
	add hl, bc
	ld a, d
	sub [hl]
	jr c, .nope
	cp 2 ; big doll width
	jr nc, .nope
	ld hl, OBJECT_MAP_Y
	add hl, bc
	ld a, e
	sub [hl]
	jr c, .nope
	cp 2 ; big doll height
	jr nc, .nope
	scf
	ret

.nope
	and a
	ret