aboutsummaryrefslogtreecommitdiffstats
path: root/engine/overworld/trainer_sight.asm
diff options
context:
space:
mode:
Diffstat (limited to 'engine/overworld/trainer_sight.asm')
-rwxr-xr-xengine/overworld/trainer_sight.asm349
1 files changed, 349 insertions, 0 deletions
diff --git a/engine/overworld/trainer_sight.asm b/engine/overworld/trainer_sight.asm
new file mode 100755
index 00000000..5a68b627
--- /dev/null
+++ b/engine/overworld/trainer_sight.asm
@@ -0,0 +1,349 @@
+_GetSpritePosition1::
+ ld hl, wSpriteStateData1
+ ld de, $4
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ call GetSpriteDataPointer
+ ld a, [hli] ; c1x4 (screen Y pos)
+ ld [$ffeb], a
+ inc hl
+ ld a, [hl] ; c1x6 (screen X pos)
+ ld [$ffec], a
+ ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
+ add hl, de
+ ld a, [hli] ; c2x4 (map Y pos)
+ ld [$ffed], a
+ ld a, [hl] ; c2x5 (map X pos)
+ ld [$ffee], a
+ ret
+
+_GetSpritePosition2::
+ ld hl, wSpriteStateData1
+ ld de, $4
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ call GetSpriteDataPointer
+ ld a, [hli] ; c1x4 (screen Y pos)
+ ld [wSavedSpriteScreenY], a
+ inc hl
+ ld a, [hl] ; c1x6 (screen X pos)
+ ld [wSavedSpriteScreenX], a
+ ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
+ add hl, de
+ ld a, [hli] ; c2x4 (map Y pos)
+ ld [wSavedSpriteMapY], a
+ ld a, [hl] ; c2x5 (map X pos)
+ ld [wSavedSpriteMapX], a
+ ret
+
+_SetSpritePosition1::
+ ld hl, wSpriteStateData1
+ ld de, $4
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ call GetSpriteDataPointer
+ ld a, [$ffeb] ; c1x4 (screen Y pos)
+ ld [hli], a
+ inc hl
+ ld a, [$ffec] ; c1x6 (screen X pos)
+ ld [hl], a
+ ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
+ add hl, de
+ ld a, [$ffed] ; c2x4 (map Y pos)
+ ld [hli], a
+ ld a, [$ffee] ; c2x5 (map X pos)
+ ld [hl], a
+ ret
+
+_SetSpritePosition2::
+ ld hl, wSpriteStateData1
+ ld de, 4
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ call GetSpriteDataPointer
+ ld a, [wSavedSpriteScreenY]
+ ld [hli], a ; c1x4 (screen Y pos)
+ inc hl
+ ld a, [wSavedSpriteScreenX]
+ ld [hl], a ; c1x6 (screen X pos)
+ ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
+ add hl, de
+ ld a, [wSavedSpriteMapY]
+ ld [hli], a ; c2x4 (map Y pos)
+ ld a, [wSavedSpriteMapX]
+ ld [hl], a ; c2x5 (map X pos)
+ ret
+
+TrainerWalkUpToPlayer::
+ ld a, [wSpriteIndex]
+ swap a
+ ld [wTrainerSpriteOffset], a
+ call ReadTrainerScreenPosition
+ ld a, [wTrainerFacingDirection]
+ and a ; SPRITE_FACING_DOWN
+ jr z, .facingDown
+ cp SPRITE_FACING_UP
+ jr z, .facingUp
+ cp SPRITE_FACING_LEFT
+ jr z, .facingLeft
+ jr .facingRight
+.facingDown
+ ld a, [wTrainerScreenY]
+ ld b, a
+ ld a, $3c ; (fixed) player screen Y pos
+ call CalcDifference
+ cp $10 ; trainer is right above player
+ ret z
+ swap a
+ dec a
+ ld c, a ; bc = steps yet to go to reach player
+ xor a
+ ld b, a ; a = direction to go to
+ jr .writeWalkScript
+.facingUp
+ ld a, [wTrainerScreenY]
+ ld b, a
+ ld a, $3c ; (fixed) player screen Y pos
+ call CalcDifference
+ cp $10 ; trainer is right below player
+ ret z
+ swap a
+ dec a
+ ld c, a ; bc = steps yet to go to reach player
+ ld b, $0
+ ld a, $40 ; a = direction to go to
+ jr .writeWalkScript
+.facingRight
+ ld a, [wTrainerScreenX]
+ ld b, a
+ ld a, $40 ; (fixed) player screen X pos
+ call CalcDifference
+ cp $10 ; trainer is directly left of player
+ ret z
+ swap a
+ dec a
+ ld c, a ; bc = steps yet to go to reach player
+ ld b, $0
+ ld a, $c0 ; a = direction to go to
+ jr .writeWalkScript
+.facingLeft
+ ld a, [wTrainerScreenX]
+ ld b, a
+ ld a, $40 ; (fixed) player screen X pos
+ call CalcDifference
+ cp $10 ; trainer is directly right of player
+ ret z
+ swap a
+ dec a
+ ld c, a ; bc = steps yet to go to reach player
+ ld b, $0
+ ld a, $80 ; a = direction to go to
+.writeWalkScript
+ ld hl, wNPCMovementDirections2
+ ld de, wNPCMovementDirections2
+ call FillMemory ; write the necessary steps to reach player
+ ld [hl], $ff ; write end of list sentinel
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ jp MoveSprite_
+
+; input: de = offset within sprite entry
+; output: hl = pointer to sprite data
+GetSpriteDataPointer:
+ push de
+ add hl, de
+ ld a, [H_SPRITEINDEX]
+ swap a
+ ld d, $0
+ ld e, a
+ add hl, de
+ pop de
+ ret
+
+; tests if this trainer is in the right position to engage the player and do so if she is.
+TrainerEngage:
+ push hl
+ push de
+ ld a, [wTrainerSpriteOffset]
+ add $2
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x2: sprite image index
+ sub $ff
+ jr nz, .spriteOnScreen ; test if sprite is on screen
+ jp .noEngage
+.spriteOnScreen
+ ld a, [wTrainerSpriteOffset]
+ add $9
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x9: facing direction
+ ld [wTrainerFacingDirection], a
+ call ReadTrainerScreenPosition
+ ld a, [wTrainerScreenY] ; sprite screen Y pos
+ ld b, a
+ ld a, $3c
+ cp b
+ jr z, .linedUpY
+ ld a, [wTrainerScreenX] ; sprite screen X pos
+ ld b, a
+ ld a, $40
+ cp b
+ jr z, .linedUpX
+ xor a
+ jp .noEngage
+.linedUpY
+ ld a, [wTrainerScreenX] ; sprite screen X pos
+ ld b, a
+ ld a, $40 ; (fixed) player X position
+ call CalcDifference ; calc distance
+ jr z, .noEngage ; exact same position as player
+ call CheckSpriteCanSeePlayer
+ jr c, .engage
+ xor a
+ jr .noEngage
+.linedUpX
+ ld a, [wTrainerScreenY] ; sprite screen Y pos
+ ld b, a
+ ld a, $3c ; (fixed) player Y position
+ call CalcDifference ; calc distance
+ jr z, .noEngage ; exact same position as player
+ call CheckSpriteCanSeePlayer
+ jr c, .engage
+ xor a
+ jp .noEngage
+.engage
+ call CheckPlayerIsInFrontOfSprite
+ ld a, [wTrainerSpriteOffset]
+ and a
+ jr z, .noEngage
+ ld hl, wFlags_0xcd60
+ set 0, [hl]
+ call EngageMapTrainer
+ ld a, $ff
+.noEngage
+ ld [wTrainerSpriteOffset], a
+ pop de
+ pop hl
+ ret
+
+; reads trainer's Y position to wTrainerScreenY and X position to wTrainerScreenX
+ReadTrainerScreenPosition:
+ ld a, [wTrainerSpriteOffset]
+ add $4
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x4 (sprite Y pos)
+ ld [wTrainerScreenY], a
+ ld a, [wTrainerSpriteOffset]
+ add $6
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x6 (sprite X pos)
+ ld [wTrainerScreenX], a
+ ret
+
+; checks if the sprite is properly lined up with the player with respect to the direction it's looking. Also checks the distance between player and sprite
+; note that this does not necessarily mean the sprite is seeing the player, he could be behind it's back
+; a: distance player to sprite
+CheckSpriteCanSeePlayer:
+ ld b, a
+ ld a, [wTrainerEngageDistance] ; how far the trainer can see
+ cp b
+ jr nc, .checkIfLinedUp
+ jr .notInLine ; player too far away
+.checkIfLinedUp
+ ld a, [wTrainerFacingDirection] ; sprite facing direction
+ cp SPRITE_FACING_DOWN
+ jr z, .checkXCoord
+ cp SPRITE_FACING_UP
+ jr z, .checkXCoord
+ cp SPRITE_FACING_LEFT
+ jr z, .checkYCoord
+ cp SPRITE_FACING_RIGHT
+ jr z, .checkYCoord
+ jr .notInLine
+.checkXCoord
+ ld a, [wTrainerScreenX] ; sprite screen X position
+ ld b, a
+ cp $40
+ jr z, .inLine
+ jr .notInLine
+.checkYCoord
+ ld a, [wTrainerScreenY] ; sprite screen Y position
+ ld b, a
+ cp $3c
+ jr nz, .notInLine
+.inLine
+ scf
+ ret
+.notInLine
+ and a
+ ret
+
+; tests if the player is in front of the sprite (rather than behind it)
+CheckPlayerIsInFrontOfSprite:
+ ld a, [wCurMap]
+ cp POWER_PLANT
+ jp z, .engage ; bypass this for power plant to get voltorb fake items to work
+ ld a, [wTrainerSpriteOffset]
+ add $4
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x4 (sprite screen Y pos)
+ cp $fc
+ jr nz, .notOnTopmostTile ; special case if sprite is on topmost tile (Y = $fc (-4)), make it come down a block
+ ld a, $c
+.notOnTopmostTile
+ ld [wTrainerScreenY], a
+ ld a, [wTrainerSpriteOffset]
+ add $6
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x6 (sprite screen X pos)
+ ld [wTrainerScreenX], a
+ ld a, [wTrainerFacingDirection] ; facing direction
+ cp SPRITE_FACING_DOWN
+ jr nz, .notFacingDown
+ ld a, [wTrainerScreenY] ; sprite screen Y pos
+ cp $3c
+ jr c, .engage ; sprite above player
+ jr .noEngage ; sprite below player
+.notFacingDown
+ cp SPRITE_FACING_UP
+ jr nz, .notFacingUp
+ ld a, [wTrainerScreenY] ; sprite screen Y pos
+ cp $3c
+ jr nc, .engage ; sprite below player
+ jr .noEngage ; sprite above player
+.notFacingUp
+ cp SPRITE_FACING_LEFT
+ jr nz, .notFacingLeft
+ ld a, [wTrainerScreenX] ; sprite screen X pos
+ cp $40
+ jr nc, .engage ; sprite right of player
+ jr .noEngage ; sprite left of player
+.notFacingLeft
+ ld a, [wTrainerScreenX] ; sprite screen X pos
+ cp $40
+ jr nc, .noEngage ; sprite right of player
+.engage
+ ld a, $ff
+ jr .done
+.noEngage
+ xor a
+.done
+ ld [wTrainerSpriteOffset], a
+ ret