-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathphysics.s
409 lines (386 loc) · 13 KB
/
physics.s
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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
MB_HITWALL = $01
MB_LANDED = $02
MB_GROUNDED = $80
BI_GROUND = $01
BI_WALL = $02
BI_CLIMB = $04
BI_DROP = $08 ;AKA navhint / turn marker
BI_SLOPEEND = $10
BI_FIRSTSLOPE = $20
BI_SLOPE = $e0
GRAVITY_ACCEL = 8
COMMON_MAX_YSPEED = 8*8
; Move actor with gravity
;
; Parameters: X actor index, actLo-Hi actor structure for parameters
; Returns: A updated movementbits
; Modifies: A,Y,various
MoveWithGravity:ldy #AD_SIDEOFFSET
lda (actLo),y
MWG_CustomSideOffset:
sta sideOffset
ldy #AD_TOPOFFSET
lda (actLo),y
sta topOffset
lda actMB,x
and #MB_GROUNDED ;Clear the one-shot flags from previous frame
sta actMB,x
MWG_DoMoveX: lda actSX,x ;If has speed, use it for X-obstacle check, else facing direction
bne MWG_HasXSpeed
lda actD,x
MWG_HasXSpeed: asl
lda actXL,x
bcc MWG_MoveRight
MWG_MoveLeft: sbc sideOffset
bmi MWG_MoveLeftCheck
adc actSX,x ;Adds one more, but should not have much effect
bpl MWG_MoveXOK
MWG_MoveLeftCheck:
lda sideOffset
ldy #-1
bmi MWG_MoveCheckCommon
MWG_MoveRight: adc sideOffset
bmi MWG_MoveRightCheck
adc actSX,x
bpl MWG_MoveXOK
MWG_MoveRightCheck:
lda #$81 ;C=0 here, subtracts one more
sbc sideOffset
ldy #1
MWG_MoveCheckCommon:
sta zpLenLo
sty loadTempReg
lda actMB,x ;If grounded, use Y-offset -1 (check above), otherwise check at current Y
ora #$7f
bmi MWG_MoveCheckGrounded
lda topOffset
beq MWG_MoveCheckGrounded ;If actor has top offset, check both ground and above
jsr GetBlockInfoXY
and #BI_WALL|BI_SLOPE|BI_SLOPEEND ;Sloped solid ground not treated as obstacles for character move
cmp #BI_WALL
beq MWG_HitWall
ldy loadTempReg
lda #$00
MWG_MoveCheckGrounded:
jsr GetBlockInfoXY
and #BI_WALL|BI_SLOPE|BI_SLOPEEND ;Sloped solid ground not treated as obstacles for character move
cmp #BI_WALL
bne MWG_MoveXOK
MWG_HitWall: lda zpLenLo
sta actXL,x
lda #MB_HITWALL
jsr SetMovementBits
lda #$00
sta actSX,x
beq MWG_MoveXDone
MWG_MoveXOK: lda actSX,x ;Actual move is not necessary with zero speed
beq MWG_MoveXDone
jsr MoveActorX
MWG_MoveXDone: lda actXL,x ;Get current within-block pixel X for slope checks
lsr
lsr
lsr
sta slopeX
lda actMB,x
bpl MWG_InAir
MWG_Grounded: jsr GetBlockInfo ;Blockinfo after X-move
sta actBlockInfo,x
lsr
bcs MWG_HasGround
lda actYL,x ;If no ground, check for block crossing for slopes
ldy actYH,x
asl
bpl MWG_UpperHalf
MWG_LowerHalf: iny
jsr GBI_Common
sta actBlockInfo,x
lsr
bcc MWG_StartFall
inc actYH,x
bne MWG_HasGround
MWG_UpperHalf: dey
jsr GBI_Common
sta actBlockInfo,x
lsr
bcc MWG_StartFall
cmp #$10
bcc MWG_StartFall ;If slope0, cannot move upward
dec actYH,x
MWG_HasGround: and #BI_SLOPE/2
ora slopeX
tay
lda slopeTbl,y
sta actYL,x
lda actMB,x
rts
MWG_StartFall:
SJ_Falling: jsr ResetAnimDelay
lda #$ff-MB_GROUNDED
ClearMovementBits:
and actMB,x
sta actMB,x
rts
MWG_InAir: jsr ApplyGravity
ldy actSY,x
bmi MWG_InAirUp
MWG_InAirDown: jsr GetBlockInfo ;Blockinfo after X-move
sta loadTempReg
lsr
bcc MWG_NotAtGround
and #BI_SLOPE/2 ;At current block?
ora slopeX
tay
lda slopeTbl,y ;If ground is above actor, cannot hit it
cmp actYL,x
bcs MWG_HasGroundLevel
lda loadTempReg
and #BI_WALL ;Exception: if already inside wall, land immediately
bne MWG_LandedSameBlock
MWG_NotAtGround:ldy actYH,x ;If not at current, also check below
iny
jsr GBI_Common
lsr
bcc MWG_NoLanding
and #BI_SLOPE/2
ora slopeX
tay
lda slopeTbl,y
ora #$80 ;(add block height to compare value)
MWG_HasGroundLevel:
sta topOffset
lda #$00
cpy #$10 ;If level ground, no need to add X-speed (would cause premature landing)
bcc MWG_IsLevel
lda actSX,x
clc
bpl MWG_XSpeedPos
eor #$ff
sec
MWG_IsLevel:
MWG_XSpeedPos: adc actSY,x ;Absolute X-speed + Y-speed to make sure we don't miss diagonal crossings
adc actYL,x
cmp topOffset
bcc MWG_NoLanding
MWG_Landed: lda topOffset ;If ground was below, adjust Y-pos 1 block down
bpl MWG_GroundPosOK
and #$7f
inc actYH,x
MWG_GroundPosOK:sta actYL,x
lda #$00
sta actSY,x
lda #MB_LANDED|MB_GROUNDED
; Set movement bits on
;
; Parameters: X actor index, A bit(s) to set
; Returns: -
; Modifies: A
SetMovementBits:ora actMB,x
sta actMB,x
rts
MWG_NoLanding: lda actSY,x
jsr MoveActorY
lda actMB,x
rts
MWG_LandedSameBlock:
lda slopeTbl,y
bpl MWG_GroundPosOK
MWG_InAirUp: jsr GetBlockInfo ;Blockinfo after X-move
lsr
bcs MWG_InAirUpHasGround
and #BI_WALL/2 ;If crossed inside a wall, must back out & retry
beq MWG_InAirUpNoLanding
lda actSX,x
jsr MoveActorXNeg
lda actXL,x
lsr
lsr
lsr
sta slopeX
jsr GetBlockInfo
lsr
bcc MWG_InAirUpNoLanding
MWG_InAirUpHasGround:
and #BI_SLOPE/2
beq MWG_InAirUpNoLanding
ora slopeX
tay
cmp #$40
bcs MWG_InAirUpSlopeLeft
MWG_InAirUpSlopeRight:
lda actSX,x ;When going up against a slope, check if combined speeds will cause going through it
beq MWG_InAirUpNoLanding
bpl MWG_InAirUpSlopeCommon
bmi MWG_InAirUpNoLanding
MWG_InAirUpSlopeLeft:
lda actSX,x
bpl MWG_InAirUpNoLanding
eor #$ff
sec
MWG_InAirUpSlopeCommon:
adc actSY,x
adc actSY,x
adc actYL,x
bmi MWG_InAirUpNoLanding
cmp slopeTbl,y
bcs MWG_LandedSameBlock
MWG_InAirUpNoLanding:
lda actSY,x
jsr MoveActorY
lda topOffset
jsr GetBlockInfoY
and #BI_WALL
beq MWG_NoHitCeiling
MWG_HitCeiling: lda #$00
sta actSY,x
sta actYL,x
inc actYH,x
MWG_NoHitCeiling:
lda actMB,x
rts
; Move projectile actor in a straight line, remove if goes outside
;
; Parameters: X actor index
; Returns: C=1 hit wall (A != 0) or was removed (A = 0)
; C=0 no wall hit
; Modifies: A,Y,loader temp vars
MoveProjectile: lda actSX,x ;Replicate MoveActor / GetBlockInfo to avoid JSRs
beq MProj_XMoveZero ;Optimize for zero X / Y speed
clc
adc actXL,x
bpl MProj_XMoveDone
ldy actSX,x
bmi MProj_XMoveLeft
inc actXH,x
bne MProj_XMoveMSBDone
MProj_XMoveLeft:dec actXH,x
MProj_XMoveMSBDone:
and #$7f
MProj_XMoveDone:
sta actXL,x
MProj_XMoveZero:lda actSY,x
beq MProj_YMoveZero
clc
adc actYL,x
bpl MProj_YMoveDone
ldy actSY,x
bmi MProj_YMoveUp
inc actYH,x
bne MProj_YMoveMSBDone
MProj_YMoveUp: dec actYH,x
bmi MProj_Remove
MProj_YMoveMSBDone:
and #$7f
MProj_YMoveDone:
sta actYL,x
MProj_YMoveZero:ldy actYH,x
lda mapTblLo,y
sta zpSrcLo
lda mapTblHi,y
sta zpSrcHi
lda actXH,x
cmp mapSizeX
bcs MProj_Remove
asl
bcc MProj_NoRowOverflow
inc zpSrcHi
MProj_NoRowOverflow:
tay
lda (zpSrcLo),y
tay
lda blkInfo,y
and #BI_WALL
beq MProj_NoWall
lda blkInfo,y
jsr CheckInsideSlope
bcs MProj_HitWall
MProj_NoWall: rts ;C=0
MProj_Remove: sec
jmp RemoveActor
MProj_HitWall: lda #$ff
rts
; Return blockinfo from actor's position with both X & Y offsets
;
; Parameters: X actor index, A signed Y offset, Y signed X offset
; Returns: A block info
; Modifies: Y, zpSrcLo-Hi,zpDestLo
GetBlockInfoXY: sty zpDestLo
clc
adc actYH,x
tay
cpy mapSizeY
bcs GBI_YOutside
lda mapTblLo,y
sta zpSrcLo
lda mapTblHi,y
sta zpSrcHi
lda actXH,x
adc zpDestLo ;C always 0
jmp GBI_Common2
; Return blockinfo from actor's position with offset
;
; Parameters: X actor index, A signed Y offset
; Returns: A block info
; Modifies: Y, zpSrcLo-Hi
GetBlockInfo1Above:
lda #-1 ;Often needed
GetBlockInfoY: clc
adc actYH,x
tay
jmp GBI_Common
; Return blockinfo from actor's position
;
; Parameters: X actor index
; Returns: A block info
; Modifies: Y, zpSrcLo-Hi
GetBlockInfo: ldy actYH,x
GBI_Common: cpy mapSizeY
bcc GBI_YNotOutside ;Continue top row above
GBI_YOutside: ldy #$00
GBI_YNotOutside:lda mapTblLo,y
sta zpSrcLo
lda mapTblHi,y
sta zpSrcHi
lda actXH,x
GBI_Common2: cmp mapSizeX
bcs GBI_OutsideHoriz
GBI_OutsideHorizDone:
asl
bcc GBI_NoRowOverflow
inc zpSrcHi
GBI_NoRowOverflow:
tay
lda (zpSrcLo),y
tay
lda blkInfo,y
rts
GBI_OutsideHoriz:
cpx #MAX_COMPLEXACT ;Bullets expand the edge column, NPCs get wall to not walk out of zone
bcc GBI_OutsideHorizNPC
cmp #$fe
bcc GBI_OutsideRight
GBI_OutsideLeft:lda #$00
beq GBI_OutsideHorizDone
GBI_OutsideRight:
lda mapSizeX
sbc #$00
bne GBI_OutsideHorizDone
GBI_OutsideHorizNPC:
lda #BI_WALL
rts
; Check whether actor is inside (below) slope
;
; Parameters: X actor index, A blockinfo from slope block
; Returns: C=1 if inside
; Modifies: Y,zpSrcLo
CheckInsideSlope:
lsr
sta zpSrcLo
lda actXL,x
lsr
lsr
lsr
ora zpSrcLo
tay
lda actYL,x
cmp slopeTbl,y
rts