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