-
Notifications
You must be signed in to change notification settings - Fork 1k
/
Copy pathtrainer_sight.asm
349 lines (340 loc) · 8.7 KB
/
trainer_sight.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
_GetSpritePosition1::
ld hl, wSpriteStateData1
ld de, SPRITESTATEDATA1_YPIXELS
ld a, [wSpriteIndex]
ldh [hSpriteIndex], a
call GetSpriteDataPointer
ld a, [hli] ; x#SPRITESTATEDATA1_YPIXELS
ldh [hSpriteScreenYCoord], a
inc hl
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
ldh [hSpriteScreenXCoord], a
ld de, wSpritePlayerStateData2MapY - wSpritePlayerStateData1XPixels
add hl, de
ld a, [hli] ; x#SPRITESTATEDATA2_MAPY
ldh [hSpriteMapYCoord], a
ld a, [hl] ; x#SPRITESTATEDATA2_MAPX
ldh [hSpriteMapXCoord], a
ret
_GetSpritePosition2::
ld hl, wSpriteStateData1
ld de, SPRITESTATEDATA1_YPIXELS
ld a, [wSpriteIndex]
ldh [hSpriteIndex], a
call GetSpriteDataPointer
ld a, [hli] ; x#SPRITESTATEDATA1_YPIXELS
ld [wSavedSpriteScreenY], a
inc hl
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
ld [wSavedSpriteScreenX], a
ld de, wSpritePlayerStateData2MapY - wSpritePlayerStateData1XPixels
add hl, de
ld a, [hli] ; x#SPRITESTATEDATA2_MAPY
ld [wSavedSpriteMapY], a
ld a, [hl] ; x#SPRITESTATEDATA2_MAPX
ld [wSavedSpriteMapX], a
ret
_SetSpritePosition1::
ld hl, wSpriteStateData1
ld de, SPRITESTATEDATA1_YPIXELS
ld a, [wSpriteIndex]
ldh [hSpriteIndex], a
call GetSpriteDataPointer
ldh a, [hSpriteScreenYCoord] ; x#SPRITESTATEDATA1_YPIXELS
ld [hli], a
inc hl
ldh a, [hSpriteScreenXCoord] ; x#SPRITESTATEDATA1_XPIXELS
ld [hl], a
ld de, wSpritePlayerStateData2MapY - wSpritePlayerStateData1XPixels
add hl, de
ldh a, [hSpriteMapYCoord] ; x#SPRITESTATEDATA2_MAPY
ld [hli], a
ldh a, [hSpriteMapXCoord] ; x#SPRITESTATEDATA2_MAPX
ld [hl], a
ret
_SetSpritePosition2::
ld hl, wSpriteStateData1
ld de, SPRITESTATEDATA1_YPIXELS
ld a, [wSpriteIndex]
ldh [hSpriteIndex], a
call GetSpriteDataPointer
ld a, [wSavedSpriteScreenY]
ld [hli], a ; x#SPRITESTATEDATA1_YPIXELS
inc hl
ld a, [wSavedSpriteScreenX]
ld [hl], a ; x#SPRITESTATEDATA1_XPIXELS
ld de, wSpritePlayerStateData2MapY - wSpritePlayerStateData1XPixels
add hl, de
ld a, [wSavedSpriteMapY]
ld [hli], a ; x#SPRITESTATEDATA2_MAPY
ld a, [wSavedSpriteMapX]
ld [hl], a ; x#SPRITESTATEDATA2_MAPX
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]
ldh [hSpriteIndex], a
jp MoveSprite_
; input: de = offset within sprite entry
; output: hl = pointer to sprite data
GetSpriteDataPointer:
push de
add hl, de
ldh a, [hSpriteIndex]
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 SPRITESTATEDATA1_IMAGEINDEX
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; x#SPRITESTATEDATA1_IMAGEINDEX
sub $ff
jr nz, .spriteOnScreen ; test if sprite is on screen
jp .noEngage
.spriteOnScreen
ld a, [wTrainerSpriteOffset]
add SPRITESTATEDATA1_FACINGDIRECTION
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; x#SPRITESTATEDATA1_FACINGDIRECTION
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, wMiscFlags
set BIT_SEEN_BY_TRAINER, [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 SPRITESTATEDATA1_YPIXELS
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; x#SPRITESTATEDATA1_YPIXELS
ld [wTrainerScreenY], a
ld a, [wTrainerSpriteOffset]
add SPRITESTATEDATA1_XPIXELS
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
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 SPRITESTATEDATA1_YPIXELS
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; x#SPRITESTATEDATA1_YPIXELS
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 SPRITESTATEDATA1_XPIXELS
ld d, $0
ld e, a
ld hl, wSpriteStateData1
add hl, de
ld a, [hl] ; x#SPRITESTATEDATA1_XPIXELS
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