1;; ======================================================================== ;;
2;;  OBJECTS -- implements code to display the tanks and bullets.            ;;
3;;                                                                          ;;
4;;  This code implements all the movement, animation and physics for the    ;;
5;;  tanks and bullets.                                                      ;;
6;;                                                                          ;;
7;;  This code isn't as clean as it could be.  For instance, MOVE_TANK0      ;;
8;;  and MOVE_TANK1 could be one function with tank number as an argument    ;;
9;;  if I were perhaps a little more careful.  (An indexed indirect          ;;
10;;  addressing mode would also be quite helpful for that as well.)          ;;
11;;                                                                          ;;
12;;  This code also has too many "manifest constants" that should be broken  ;;
13;;  out to equates or something.                                            ;;
14;;                                                                          ;;
15;; ------------------------------------------------------------------------ ;;
16;;  GLOBAL VARIABLES REQUIRED BY THIS MODULE                                ;;
17;;                                                                          ;;
18;;  Name        Width   Purpose                                             ;;
19;;  TNKx_VEL    8-bit   Desired velocity of tank * 8.  -2, 0 or 2.          ;;
20;;  TNKx_MOV    8-bit   Actual movement of tank * 8.  -2, -1, 0, 1, or 2.   ;;
21;;  TNKx_AVL    8-bit   Angular velocity of tank's gun turret.  -1, 0, or 1 ;;
22;;  TNKx_ANG    8-bit   Angle of tank's turret divided by 10.  0 thru 18.   ;;
23;;  TNKx_POW    8-bit   Firing strength configured for tank.                ;;
24;;  TNKx_PTS    16-bit  Number of points scored by tank (up to 65535).      ;;
25;;  TNKx_FLP    8-bit   Flag:  Tank now faces opposite direction.           ;;
26;;  DO_STATS    8-bit   Flag:  If non-zero, update stats next frame.        ;;
27;;  B0_TICK     8-bit   Count:  Ignore bullet 0 collisions while != 0.      ;;
28;;  B1_TICK     8-bit   Count:  Ignore bullet 1 collisions while != 0.      ;;
29;;  AVL_TICK    8-bit   Count:  Apply angular vel. to turrets every N ticks ;;
30;;  BULx_XVL    16-bit  X velocity (8.8) of bullet                          ;;
31;;  BULx_YVL    16-bit  Y velocity (8.8) of bullet                          ;;
32;;  MOB_DIS     16-bit  MOB collision table dispatch pointer (from MOB_LL)  ;;
33;;  MOB_IGN     16-bit  MOB collision ignore table pointer (from MOB_LL)    ;;
34;;                                                                          ;;
35;; ------------------------------------------------------------------------ ;;
36;;  EXTERNAL STRUCTURES REFERENCED BY THIS MODULE                           ;;
37;;                                                                          ;;
38;;      MOB_PIC     MOB picture table (from MOB_LL)                         ;;
39;;      MOB_ATR     MOB attribute table (from MOB_LL)                       ;;
40;;      MOB_XYP     MOB X/Y position table (from MOB_LL)                    ;;
41;;      GFX.xxx     Graphics picture numbers associated with game elements  ;;
42;;      ATR.xxx     MOB attribute numbers associated w/ game elements       ;;
43;;      MNUM.xxx    MOB numbers assigned to individual game elements        ;;
44;;      SINCOS      Sine/Cosine table for initial bullet velocity           ;;
45;;      TURTBL      Turret picture-number lookup table                      ;;
46;;      BULOFS      Bullet pixel offset by turret angle lookup table        ;;
47;;      FACE        MOB attribute lookup for tank facing left/right         ;;
48;;                                                                          ;;
49;; ------------------------------------------------------------------------ ;;
50;;  FUNCTIONS DEFINED IN THIS MODULE                                        ;;
51;;                                                                          ;;
52;;      INIT_TANK   Initialize the two tanks                                ;;
53;;      MOVE_TANK0  Move tank 0 by the amount in R2                         ;;
54;;      MOVE_TANK1  Move tank 1 by the amount in R2                         ;;
55;;      MOVE_TUR    Move turret for tank in R0 by amount in R2              ;;
56;;      UPD_TANKS   Do per-frame updates for tanks (movement etc.)          ;;
57;;      UPD_BULLET  Do per-frame updates for bullets (movement etc.)        ;;
58;;      HIT_BULLET  Handle bullet collisions                                ;;
59;;      FIRE_BULLET Make a bullet airborne for a tank.                      ;;
60;; ======================================================================== ;;
61
62
63;; ======================================================================== ;;
64;;  INIT_TANK -- Initializes the two tanks.                                 ;;
65;; ======================================================================== ;;
66INIT_TANK   PROC
67            PSHR    R5
68
69            MVII    #DISPATCH,  R0
70            MVOD    R0,         MOB_DIS
71            MVII    #IGNORE,    R0
72            MVOD    R0,         MOB_IGN
73
74            ; MOBs 0..2 are first tank
75
76            ; tank body
77            CALL    MOB_CREATE
78            DECLE   MNUM.t0_body
79            DECLE   pack(87, 10)
80            DECLE   ATR.r_tbody
81            DECLE   pack(GFX.tbody+1, GFX.tbody)
82
83            ; tank turret
84            CALL    MOB_CREATE
85            DECLE   MNUM.t0_tur
86            DECLE   pack(87, 10)
87            DECLE   ATR.r_tur
88            DECLE   pack(GFX.turbot, GFX.tur0)
89
90
91            ; tank tread
92            CALL    MOB_CREATE
93            DECLE   MNUM.t0_tread
94            DECLE   pack(87, 10)
95            DECLE   ATR.r_tread
96            DECLE   pack(GFX.none, GFX.tread1)
97
98
99
100
101            ; MOBs 3..5 are first tank
102
103            ; tank body
104            CALL    MOB_CREATE
105            DECLE   MNUM.t1_body
106            DECLE   pack(87, 153)
107            DECLE   ATR.l_tbody
108            DECLE   pack(GFX.tbody+1, GFX.tbody)
109
110            ; tank turret
111            CALL    MOB_CREATE
112            DECLE   MNUM.t1_tur
113            DECLE   pack(87, 153)
114            DECLE   ATR.l_tur
115            DECLE   pack(GFX.turbot, GFX.tur0)
116
117
118            ; tank tread
119            CALL    MOB_CREATE
120            DECLE   MNUM.t1_tread
121            DECLE   pack(87, 153)
122            DECLE   ATR.l_tread
123            DECLE   pack(GFX.none, GFX.tread0)
124
125
126            ;; Set up the other tank variables
127
128            CLRR    R0
129            MVO     R0,     TNK0_ANG        ; turret faces hard right
130            MVO     R0,     TNK0_AVL        ; turret isn't moving
131            MVO     R0,     TNK1_AVL        ; turret isn't moving
132
133            MVII    #18,    R0
134            MVO     R0,     TNK1_ANG        ; turret faces hard left
135
136            MVII    #5,     R0
137            MVO     R0,     TNK0_POW        ; initial firing strength of 5
138            MVO     R0,     TNK1_POW        ; initial firing strength of 5
139
140            PULR    PC
141            ENDP
142
143
144;; ======================================================================== ;;
145;;  MOVE_TANK0 -- Move tank 0 left or right by amount in R2.                ;;
146;; ======================================================================== ;;
147MOVE_TANK0  PROC
148            PSHR    R5
149
150            CALL    MOB_MOVE_M.0            ; DX is already in R2
151            DECLE   $0000                   ; make DY = 0.
152            DECLE   $07                     ; Tank #0 is MOBs 0..2
153
154            MVI     XYPAddr(MNUM.t0, x_hi), R1  ; tank 0's X position
155            CMPI    #8,         R1
156            BGT     @@ok_left
157
158            CLRR    R1
159            MVO     R1,         TNK0_MOV    ; halt the tank
160
161            CALL    MOB_GOTO_M              ;
162            DECLE   $08E0                   ; clamp left border, rounded up
163            DECLE   87*256                  ;
164            DECLE   $07                     ; Tank #0 is MOBs 0..2
165
166            B       @@ok_right
167
168@@ok_left:  CMPI    #151,       R1
169            BLT     @@ok_right
170
171            CLRR    R1
172            MVO     R1,         TNK0_MOV    ; halt the tank
173
174            CALL    MOB_GOTO_M              ;
175            DECLE   $9700                   ; clamp exactly to right border
176            DECLE   87*256                  ;
177            DECLE   $07                     ; Tank #0 is MOBs 0..2
178
179
180@@ok_right:
181
182            ; Compute tread alignment given final resting position of tank0
183            MVI     XYPAddr(MNUM.t0, x_hi), R1  ; tank 0's X position
184            MOD3    R1,         R3          ; R1 = R1 MOD 3, using R0 as temp
185
186            ; figure out what way we're facing so we can negate the MOD
187
188            MVI     AtrAddr(MNUM.t0_tread), R2   ; tank 0's tread attribute
189            CMPI    #ATR.r_tread,R2         ; is it right-facing?
190            BEQ     @@right                 ; yes:  Don't flip
191            NEGR    R1                      ; \   no:  Flip in such a way
192            BEQ     @@ok                    ;  |- that the flipped tread
193            ADDI    #3,         R1          ; /   aligns to the non-flipped
194@@ok:
195@@right:
196            ; store new picture number for tread, one of tread0 thru tread2.
197            ADDI    #GFX.tread0+$80, R1
198            MVO     R1,         PicAddr(MNUM.t0_tread, top)
199
200            PULR    R5
201            B       FLG_STICSH
202
203            ENDP
204
205;; ======================================================================== ;;
206;;  MOVE_TANK1 -- Move tank 1 left or right by amount in R2.                ;;
207;; ======================================================================== ;;
208MOVE_TANK1  PROC
209            PSHR    R5
210
211            CALL    MOB_MOVE_M.0            ; DX is already in R2
212            DECLE   $0000                   ; make DY = 0.
213            DECLE   $38                     ; Tank #1 is MOBs 3..5
214
215            MVI     XYPAddr(MNUM.t1, x_hi), R1  ; tank 1's X position
216            CMPI    #159,       R1
217            BLT     @@ok_right
218
219            CLRR    R1
220            MVO     R1,         TNK1_MOV    ; halt the tank
221
222            CALL    MOB_GOTO_M              ;
223            DECLE   159*256                 ; clamp exactly to right border
224            DECLE   87*256                  ;
225            DECLE   $38                     ; Tank #1 is MOBs 3..5
226
227            B       @@ok_left
228
229@@ok_right: CMPI    #16,        R1
230            BGT     @@ok_left
231
232            CLRR    R1
233            MVO     R1,         TNK1_MOV    ; halt the tank
234
235            CALL    MOB_GOTO_M              ;
236            DECLE   $10E0                   ; clamp exactly to left border
237            DECLE   87*256                  ;
238            DECLE   $38                     ; Tank #1 is MOBs 3..5
239
240@@ok_left:
241
242            ; Compute tread alignment given final resting position of tank1
243            MVI     XYPAddr(MNUM.t1, x_hi), R1  ; tank 1's X position
244            MOD3    R1,         R3          ; R1 = R1 MOD 3, using R0 as temp
245
246            ; figure out what way we're facing so we can negate the MOD
247
248            MVI     AtrAddr(MNUM.t1_tread), R2   ; tank 1's tread attribute
249            CMPI    #ATR.r_tread,R2         ; is it right-facing?
250            BEQ     @@right                 ; yes:  Don't flip
251            NEGR    R1                      ; \   no:  Flip in such a way
252            BEQ     @@ok                    ;  |- that the flipped tread
253            ADDI    #3,         R1          ; /   aligns to the non-flipped
254@@ok:
255@@right:
256            ; store new picture number for tread, one of tread0 thru tread2.
257            ADDI    #GFX.tread0+$80, R1
258            MVO     R1,         PicAddr(MNUM.t1_tread, top)
259
260            PULR    R5
261            B       FLG_STICSH
262
263            ENDP
264
265;; ======================================================================== ;;
266;;  MOVE_TUR -- Move a turret CW/CCW by amount in R2.  Tank # in R0.        ;;
267;; ======================================================================== ;;
268MOVE_TUR    PROC
269            PSHR    R5
270
271            MVII    #1,         R1
272            MVO     R1,         DO_STATS
273
274            MVII    #TNK0_ANG,  R1          ;\__ Index to requested tank
275            ADDR    R0,         R1          ;/
276
277            NEGR    R2                      ; CW is negative angle
278            ADD@    R1,         R2          ; Add turret rotation to current
279            BGE     @@ok_lo                 ; don't let it go negative
280            CLRR    R2                      ; clamp to 0
281@@ok_lo:    CMPI    #18,        R2          ; don't let it go above 180
282            BLE     @@ok_hi                 ;
283            MVII    #18,        R2          ; clamp to 180
284
285@@ok_hi:    MVO@    R2,         R1          ; store new turret position
286
287            MVII    #AtrAddr(MNUM.t0), R5   ; might need to face tank other way
288            MVII    #PicAddr(MNUM.t0_tur,top), R3
289            TSTR    R0
290            BEQ     @@tank0
291            MVII    #AtrAddr(MNUM.t1), R5   ; might need to face tank other way
292            MVII    #PicAddr(MNUM.t1_tur,top), R3
293@@tank0:
294
295            ADDI    #TURTBL,    R2          ; Look up required turret angle
296            MVI@    R2,         R2
297            SARC    R2,         2
298            MVO@    R2,         R3          ; store turret picture # for tank
299
300            BOV     @@no_face
301            MVII    #FACE.lft,  R4
302            BC      @@face_left
303            MVII    #FACE.rgt,  R4
304@@face_left:
305
306            REPEAT  3
307            MVI@    R4,         R1
308            MVO@    R1,         R5
309            ENDR
310
311            MVII    #1,         R1
312            MVII    #TNK0_FLP,  R2
313            ADDR    R0,         R2
314            MVO@    R1,         R2
315
316            PULR    R5
317            B       FLG_STICSH
318
319@@no_face:  PULR    PC
320            ENDP
321
322
323;; ======================================================================== ;;
324;;  UPD_TANKS -- Per-frame updates for tanks.                               ;;
325;; ======================================================================== ;;
326UPD_TANKS   PROC
327            PSHR    R5
328
329            ;; ------------------------------------------------------------ ;;
330            ;;  If the two tanks collide this tick, then the actual vel     ;;
331            ;;  of both is the average of the two requested velocities.     ;;
332            ;;  Otherwise, the velocity of each is the requested velocity.  ;;
333            ;; ------------------------------------------------------------ ;;
334            MVI     TNK0_VEL,   R0              ; get tank 0's desired vel
335            MVI     TNK1_VEL,   R1              ; get tank 1's desired vel
336
337            MVII    #XYPAddr(MNUM.t1, x_lo), R4 ;\
338            SDBD                                ; |
339            MVI@    R4,         R2              ; |_ Find the distance between
340            MVII    #XYPAddr(MNUM.t0, x_lo), R4 ; |  the two tanks.
341            SDBD                                ; |
342            SUB@    R4,         R2              ;/
343
344            CMPI    #$0801,     R2              ; Are they in contact?
345            BC      @@no_hit
346
347            ; only do this if they're moving towards each other.  this isn't
348            ; a towing service.
349
350            SWAP    R0                          ; |-- skip out if tank 0
351            TSTR    R0
352            BMI     @@no_hit0                   ;/    is moving left
353            SWAP    R1                          ; |-- skip out if tank 1
354            TSTR    R1
355            BEQ     @@hit                       ; |   is moving right
356            BPL     @@no_hit1                   ;/
357@@hit:
358
359            ADDR    R1,         R0              ;\
360            SAR     R0,         1               ; |  They're in contact, so
361            SWAP    R0,         1               ; |_ each has an actual vel.
362            MVO     R0,         TNK0_MOV        ; |  that's the average of the
363            MVO     R0,         TNK1_MOV        ; |  two desired velocities.
364            B       @@done_vel                  ;/
365
366
367@@no_hit1:  SWAP    R1
368@@no_hit0:  SWAP    R0
369@@no_hit:   MVO     R0,         TNK0_MOV
370            MVO     R1,         TNK1_MOV
371@@done_vel:
372
373
374            ;; ------------------------------------------------------------ ;;
375            ;;  Only do turret updates every few frames.                    ;;
376            ;; ------------------------------------------------------------ ;;
377            MVI     AVL_TICK,   R0
378            DECR    R0
379            BPL     @@no_tur_0
380
381            ;; ------------------------------------------------------------ ;;
382            ;;  Update Tank 0's turret position based on angular velocity.  ;;
383            ;; ------------------------------------------------------------ ;;
384            MVI     TNK0_AVL,   R2
385            DECR    R2
386            BMI     @@no_tur_0
387            BNEQ    @@tur_0_cw
388            DECR    R2
389@@tur_0_cw: CLRR    R0
390            CALL    MOVE_TUR
391@@no_tur_0:
392            ;; ------------------------------------------------------------ ;;
393            ;;  Update Tank 0's position based on its velocity.             ;;
394            ;; ------------------------------------------------------------ ;;
395            MVI     TNK0_MOV,   R2
396            SWAP    R2
397            CMP     TNK0_FLP,   R2  ; forces 'MOVE' call if tank flips l/r
398            BEQ     @@no_move_0
399            MVO     R2,         TNK0_FLP
400            SAR     R2,         2
401            SAR     R2,         1
402            CALL    MOVE_TANK0
403@@no_move_0:
404
405            MVI     AVL_TICK,   R0
406            DECR    R0
407            BPL     @@no_tur_1
408
409            ;; ------------------------------------------------------------ ;;
410            ;;  Update Tank 1's turret position based on angular velocity.  ;;
411            ;; ------------------------------------------------------------ ;;
412            MVI     TNK1_AVL,   R2
413            DECR    R2
414            BMI     @@no_tur_1
415            BNEQ    @@tur_1_cw
416            DECR    R2
417@@tur_1_cw: MVII    #1,         R0
418            CALL    MOVE_TUR
419@@no_tur_1:
420
421            ;; ------------------------------------------------------------ ;;
422            ;;  Update Tank 1's position based on its velocity.             ;;
423            ;; ------------------------------------------------------------ ;;
424            MVI     TNK1_MOV,   R2
425            SWAP    R2
426            CMP     TNK1_FLP,   R2  ; forces 'MOVE' call if tank flips l/r
427            BEQ     @@no_move_1
428            MVO     R2,         TNK1_FLP
429            SAR     R2,         2
430            SAR     R2,         1
431            CALL    MOVE_TANK1
432@@no_move_1:
433
434            MVI     AVL_TICK,   R0
435            DECR    R0
436            BPL     @@tick_ok
437            MVII    #3,         R0
438@@tick_ok:  MVO     R0,         AVL_TICK
439
440
441            PULR    PC
442            ENDP
443
444
445;; ======================================================================== ;;
446;;  UPD_BULLET -- Update bullet positions, etc.                             ;;
447;; ======================================================================== ;;
448UPD_BULLET  PROC
449            PSHR    R5
450
451            ;; ------------------------------------------------------------ ;;
452            ;;  Update the "bullet no-hit" timers.                          ;;
453            ;; ------------------------------------------------------------ ;;
454            MVI     B0_TICK,    R0
455            DECR    R0
456            BMI     @@b0_live
457            MVO     R0,         B0_TICK
458@@b0_live:
459            MVI     B1_TICK,    R0
460            DECR    R0
461            BMI     @@b1_live
462            MVO     R0,         B1_TICK
463@@b1_live:
464            ;; ------------------------------------------------------------ ;;
465            ;;  Update bullet 0.                                            ;;
466            ;; ------------------------------------------------------------ ;;
467            MVI     AtrAddr(MNUM.b0),R0     ; Take a look at bullet 0's MOB
468            CMPI    #ATR.bullet,R0          ; Is this (still) a bullet?
469            BNEQ    @@done_b0               ; no? skip it.
470
471            ; make sure bullet 0 doesn't go below ground level.  If it's
472            ; on the ground, just leave it there
473            MVI     XYPAddr(MNUM.b0,y_hi), R0
474            CMPI    #88,        R0
475            BGE     @@done_b0
476
477            ; accelerate bullet 0 by gravity and then move it.
478            MVI     BUL0_YVL,   R3          ;\
479            ADDI    #GRAVITY,   R3          ; |- Accelerate it by gravity
480            CMPI    #$00FF,     R3          ;/
481            BLE     @@b0v_ok                ;
482            MVII    #$00FF,     R3          ; clamp y velocity to $00.FF
483@@b0v_ok:
484            MVO     R3,         BUL0_YVL    ; store updated y velocity
485            MVI     BUL0_XVL,   R2          ; get bullet 0's x velocity
486            CALL    MOB_MOVE.1              ; move bullet 0
487            DECLE   MNUM.b0
488
489            MVI     XYPAddr(MNUM.b0,x_hi), R0   ;\
490            CMPI    #1,         R0              ; |_ destroy bullet if it
491            BLT     @@kill_b0                   ; |  goes offscreen
492            CMPI    #159,       R0              ;/
493            BLE     @@done_b0
494
495@@kill_b0:  CALL    MOB_DESTROY
496            DECLE   MNUM.b0
497
498@@done_b0:
499
500            ;; ------------------------------------------------------------ ;;
501            ;;  Update bullet 1.                                            ;;
502            ;; ------------------------------------------------------------ ;;
503            MVI     AtrAddr(MNUM.b1),R0     ; Take a look at bullet 1's MOB
504            CMPI    #ATR.bullet,R0          ; Is this (still) a bullet?
505            BNEQ    @@done_b1               ; no? skip it.
506
507            ; make sure bullet 1 doesn't go below ground level.  If it's
508            ; on the ground, just leave it there
509            MVI     XYPAddr(MNUM.b1,y_hi), R0
510            CMPI    #88,        R0
511            BGE     @@done_b1
512
513            ; accelerate bullet 1 by gravity and then move it.
514            MVI     BUL1_YVL,   R3          ;\
515            ADDI    #GRAVITY,   R3          ; |- Accelerate it by gravity
516            CMPI    #$00FF,     R3          ;/
517            BLE     @@b1v_ok                ;
518            MVII    #$00FF,     R3          ; clamp y velocity to $00.FF
519@@b1v_ok:
520            MVO     R3,         BUL1_YVL    ; store updated y velocity
521            MVI     BUL1_XVL,   R2          ; get bullet 1's x velocity
522            CALL    MOB_MOVE.1              ; move bullet 1
523            DECLE   MNUM.b1
524
525            MVI     XYPAddr(MNUM.b1,x_hi), R0   ;\
526            CMPI    #1,         R0              ; |_ destroy bullet if it
527            BLT     @@kill_b1                   ; |  goes offscreen
528            CMPI    #159,       R0              ;/
529            BLE     @@done_b1
530
531@@kill_b1:  CALL    MOB_DESTROY
532            DECLE   MNUM.b1
533
534@@done_b1:
535
536            ;; ------------------------------------------------------------ ;;
537            ;;  Update bullet 0's explosion, if it's exploding.             ;;
538            ;; ------------------------------------------------------------ ;;
539            MVI     PicAddr(MNUM.b0,top),R0 ; Take a look at bullet 0's MOB
540
541            CMPI    #GFX.exp0,  R0          ;\
542            BLT     @@done_e0               ; |_ is it one of the explosion
543            CMPI    #GFX.exp7,  R0          ; |  frames?
544            BGT     @@done_e0               ;/
545
546            BNEQ    @@next_e0               ; Is it one of the first 7?
547
548            CALL    MOB_DESTROY             ;\__ take down the animation
549            DECLE   MNUM.b0                 ;/   on its last frame
550            B       @@done_e0
551@@next_e0:
552            INCR    R0                      ;\
553            ADDI    #$80,       R0          ; |- advance the explosion anim
554            MVO     R0, PicAddr(MNUM.b0,top);/   by one frame.
555@@done_e0:
556
557            ;; ------------------------------------------------------------ ;;
558            ;;  Update bullet 1's explosion, if it's exploding.             ;;
559            ;; ------------------------------------------------------------ ;;
560            MVI     PicAddr(MNUM.b1,top),R0 ; Take a look at bullet 1's MOB
561
562            CMPI    #GFX.exp0,  R0          ;\
563            BLT     @@done_e1               ; |_ is it one of the explosion
564            CMPI    #GFX.exp7,  R0          ; |  frames?
565            BGT     @@done_e1               ;/
566
567            BNEQ    @@next_e1               ; Is it one of the first 7?
568
569            CALL    MOB_DESTROY             ;\__ take down the animation
570            DECLE   MNUM.b1                 ;/   on its last frame
571            B       @@done_e1
572@@next_e1:
573            INCR    R0                      ;\
574            ADDI    #$80,       R0          ; |- advance the explosion anim
575            MVO     R0, PicAddr(MNUM.b1,top);/   by one frame.
576@@done_e1:
577            PULR    R5
578            B       FLG_STICSH
579            ENDP
580
581
582;; ======================================================================== ;;
583;;  HIT_BULLET -- Handle bullet collisions w/ tanks, ground, walls.         ;;
584;; ======================================================================== ;;
585HIT_BULLET  PROC
586@@0:        PSHR    R5
587
588            ;; ------------------------------------------------------------ ;;
589            ;;  Filter out collisions during first tick or so of bullet's   ;;
590            ;;  life, since it might strike the firing tank itself on the   ;;
591            ;;  way out if the tank is moving.  We want to ignore that.     ;;
592            ;; ------------------------------------------------------------ ;;
593            CLRR    R0
594            CMP     B0_TICK,    R0
595            BNEQ    @@leave
596
597            ;; ------------------------------------------------------------ ;;
598            ;;  Convert bullets into explosions.                            ;;
599            ;; ------------------------------------------------------------ ;;
600            MVI     PicAddr(MNUM.b0, top), R0   ;\_ don't destroy explosions
601            CMPI    #GFX.bullet, R0             ;/
602            BNEQ    @@already_exploding
603
604            ; Make this an explosion.
605            MVII    #GFX.exp0,  R0
606            MVO     R0,         PicAddr(MNUM.b0, top)
607            MVII    #ATR.explode, R0
608            MVO     R0,         AtrAddr(MNUM.b0)
609
610            ; Slide it over 3 pixels to center it
611            MVI     XYPAddr(MNUM.b0, x_hi), R0
612            ADDI    #3,         R0
613            MVO     R0, XYPAddr(MNUM.b0, x_hi)
614
615            CLRR    R0
616            MVO     R0,         BUL0_XVL
617            MVO     R0,         BUL0_YVL
618            B       @@already_exploding
619
620
621
622
623
624@@1:        PSHR    R5
625
626            ;; ------------------------------------------------------------ ;;
627            ;;  Filter out collisions during first tick or so of bullet's   ;;
628            ;;  life, since it might strike the firing tank itself on the   ;;
629            ;;  way out if the tank is moving.  We want to ignore that.     ;;
630            ;; ------------------------------------------------------------ ;;
631            CLRR    R0
632            CMP     B1_TICK,    R0
633            BNEQ    @@leave
634
635            ;; ------------------------------------------------------------ ;;
636            ;;  Convert bullets into explosions.                            ;;
637            ;; ------------------------------------------------------------ ;;
638            MVI     PicAddr(MNUM.b1, top), R0   ;\_ don't destroy explosions
639            CMPI    #GFX.bullet, R0             ;/
640            BNEQ    @@already_exploding
641
642            ; Make this an explosion.
643            MVII    #GFX.exp0,  R0
644            MVO     R0,         PicAddr(MNUM.b1, top)
645            MVII    #ATR.explode, R0
646            MVO     R0,         AtrAddr(MNUM.b1)
647
648            ; Slide it over 4 pixels to center it
649            MVI     XYPAddr(MNUM.b1, x_hi), R0
650            ADDI    #4,         R0
651            MVO     R0, XYPAddr(MNUM.b1, x_hi)
652
653            CLRR    R0
654            MVO     R0,         BUL1_XVL
655            MVO     R0,         BUL1_YVL
656
657@@already_exploding:
658
659            ;; ------------------------------------------------------------ ;;
660            ;;  Check to see whether this bullet/explosion hit one or both  ;;
661            ;;  tanks.  For every frame that an explosion hits one tank,    ;;
662            ;;  the other tank gets a point.                                ;;
663            ;; ------------------------------------------------------------ ;;
664            MOVR    R2,         R3              ; save explosion mask
665
666            ANDI    #$07,       R2              ; did we hit tank 0?
667            BEQ     @@no_tank_0
668
669            MVI     TNK1_PTS,   R0
670            INCR    R0
671            BEQ     @@no_tank_0                 ; prevent overflow
672            MVO     R0,         TNK1_PTS
673            MVII    #1,         R1
674            MVO     R1,         DO_STATS
675
676@@no_tank_0:
677
678            ANDI    #$38,       R3              ; did we hit tank 0?
679            BEQ     @@no_tank_1
680
681            MVI     TNK0_PTS,   R0
682            INCR    R0
683            BEQ     @@no_tank_1                 ; prevent overflow
684            MVO     R0,         TNK0_PTS
685
686            MVII    #1,         R1
687            MVO     R1,         DO_STATS
688
689@@no_tank_1:
690
691@@leave:    PULR    PC
692            ENDP
693
694;; ======================================================================== ;;
695;;  FIRE_BULLET -- Fires a bullet for the tank in R0.                       ;;
696;; ======================================================================== ;;
697FIRE_BULLET PROC
698            PSHR    R5
699
700            ;; ------------------------------------------------------------ ;;
701            ;;  Check to see if this tank already has a bullet in the air.  ;;
702            ;; ------------------------------------------------------------ ;;
703            MVII    #AtrAddr(MNUM.b0),R1;\_ Point to this tank's bullet
704            ADDR    R0,         R1      ;/  attribute
705
706            MVI@    R1,         R1      ; get the attribute for this bullet
707            TSTR    R1                  ;\__ if it's non-zero, it's either
708            BNEQ    @@leave             ;/   a bullet or explosion.  Leave.
709
710            MVII    #4,         R3      ; Initial value for "no-hit" timer
711            MVII    #ATR.l_tur, R1      ; will need to determine tank's dir.
712
713            TSTR    R0                  ;\__ load parameters for appropriate
714            BEQ     @@t0                ;/   tank
715
716@@t1:       MVO     R3,         B1_TICK         ; set bullet 1's no-hit timer
717            MVI     TNK1_ANG,   R3              ; get tank 1's firing angle
718            CMP     AtrAddr(MNUM.t1_tur),   R1  ;\   add 1 if facing left
719            BNEQ    @@t1_rgt                    ; |- to distinguish 90 deg
720            INCR    R3                          ;/   left from 90 deg right
721@@t1_rgt:   MVII    #XYPAddr(MNUM.t1,x_hi), R1  ; point R1 to tank 1's X coord
722            B       @@tdone
723
724@@t0:       MVO     R3,         B0_TICK         ; set bullet 0's no-hit timer
725            MVI     TNK0_ANG,   R3              ; get tank 0's firing angle
726            CMP     AtrAddr(MNUM.t0_tur),   R1  ;\   add 1 if facing left
727            BNEQ    @@t0_rgt                    ; |- to distinguish 90 deg
728            INCR    R3                          ;/   left from 90 deg right
729@@t0_rgt:   MVII    #XYPAddr(MNUM.t0,x_hi), R1  ; point R1 to tank 0's X coord
730
731@@tdone:
732
733            ;; ------------------------------------------------------------ ;;
734            ;;  Compute the initial position for the bullet based on tank's ;;
735            ;;  position and turret angle.  R3 has turret angle.            ;;
736            ;; ------------------------------------------------------------ ;;
737
738            MVI@    R1,         R2      ; get tank's X position into lower byte
739            ADDI    #87*256,    R2      ; Set Y coordinate to base of tank
740            ADDI    #BULOFS,    R3      ; point to packed X/Y offset for bullet
741            SUB@    R3,         R2      ; move the bullet up/left as necessary
742
743            PSHR    R0                  ; save the tank #
744
745            ;; ------------------------------------------------------------ ;;
746            ;;  Create the MOB for the bullet.                              ;;
747            ;; ------------------------------------------------------------ ;;
748            MVII    #MNUM.b0,   R1      ;\__ Pick the bullet based on tank#
749            ADDR    R0,         R1      ;/
750
751            CALL    MOB_CREATE.2                ;\
752            DECLE   ATR.bullet                  ; |- make the bullet
753            DECLE   pack(GFX.none, GFX.bullet)  ;/
754
755            PULR    R0                  ; restore tank # from stack
756
757            ;; ------------------------------------------------------------ ;;
758            ;;  Setup the X/Y velocity for the bullet.  We use these eqs:   ;;
759            ;;    x_vel = (fire_power + 2) * cos(angle) / 4 + tank_x_vel    ;;
760            ;;    y_vel = (fire_power + 2) * sin(angle) / 4                 ;;
761            ;; ------------------------------------------------------------ ;;
762            MVII    #BUL0_XVL,  R4      ;\
763            ADDR    R0,         R4      ; |- point to the correct bullet's
764            ADDR    R0,         R4      ;/   velocity
765
766            MVII    #SINCOS,    R5      ;\
767            MVII    #TNK0_ANG,  R2      ; |
768            ADDR    R0,         R2      ; |- Index into Sine/Cosine table
769            ADD@    R2,         R5      ; |  based on this tank's turret angle
770            ADD@    R2,         R5      ;/
771
772            ADDI    #TNK0_POW-TNK0_ANG, R2  ;\__ Get tank's firing power
773            MVI@    R2,         R1          ;/   into R1.
774            ADDI    #2,         R1          ; Add 2, since '1' is pretty wimpy
775
776            SUBI    #TNK0_POW-TNK0_MOV, R2  ;\
777            MVI@    R2,         R2          ; |_ Initialize bullet velocity
778            SWAP    R2                      ; |  to this tank's horizontal
779            SAR     R2,         1           ;/   velocity * 4.
780
781            CLRR    R3                  ; initialize vertical vel to 0.
782
783@@mul_loop  ; Multiply sine/cosine by tank's firing power.
784            ADD@    R5,         R2      ; Add cosine to horizontal
785            ADD@    R5,         R3      ; Add sine to vertical
786            SUBI    #2,         R5      ; keep pointing to to same sine/cosine
787            DECR    R1                  ;\__ multiply iteratively
788            BNEQ    @@mul_loop          ;/
789
790            SAR     R2,         2       ; Divide X velocity by 4
791            SAR     R3,         2       ; Divide Y velocity by 4
792
793            MVO@    R2,         R4      ; store X velocity
794            MVO@    R3,         R4      ; store Y velocity
795
796@@leave:    PULR    PC
797
798            ENDP
799
800
801;* ======================================================================== *;
802;*  This program is free software; you can redistribute it and/or modify    *;
803;*  it under the terms of the GNU General Public License as published by    *;
804;*  the Free Software Foundation; either version 2 of the License, or       *;
805;*  (at your option) any later version.                                     *;
806;*                                                                          *;
807;*  This program is distributed in the hope that it will be useful,         *;
808;*  but WITHOUT ANY WARRANTY; without even the implied warranty of          *;
809;*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *;
810;*  General Public License for more details.                                *;
811;*                                                                          *;
812;*  You should have received a copy of the GNU General Public License       *;
813;*  along with this program; if not, write to the Free Software             *;
814;*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *;
815;* ======================================================================== *;
816;*                   Copyright (c) 2003, Joseph Zbiciak                     *;
817;* ======================================================================== *;
818