;; ======================================================================== ;; ;; OBJECTS -- implements code to display the tanks and bullets. ;; ;; ;; ;; This code implements all the movement, animation and physics for the ;; ;; tanks and bullets. ;; ;; ;; ;; This code isn't as clean as it could be. For instance, MOVE_TANK0 ;; ;; and MOVE_TANK1 could be one function with tank number as an argument ;; ;; if I were perhaps a little more careful. (An indexed indirect ;; ;; addressing mode would also be quite helpful for that as well.) ;; ;; ;; ;; This code also has too many "manifest constants" that should be broken ;; ;; out to equates or something. ;; ;; ;; ;; ------------------------------------------------------------------------ ;; ;; GLOBAL VARIABLES REQUIRED BY THIS MODULE ;; ;; ;; ;; Name Width Purpose ;; ;; TNKx_VEL 8-bit Desired velocity of tank * 8. -2, 0 or 2. ;; ;; TNKx_MOV 8-bit Actual movement of tank * 8. -2, -1, 0, 1, or 2. ;; ;; TNKx_AVL 8-bit Angular velocity of tank's gun turret. -1, 0, or 1 ;; ;; TNKx_ANG 8-bit Angle of tank's turret divided by 10. 0 thru 18. ;; ;; TNKx_POW 8-bit Firing strength configured for tank. ;; ;; TNKx_PTS 16-bit Number of points scored by tank (up to 65535). ;; ;; TNKx_FLP 8-bit Flag: Tank now faces opposite direction. ;; ;; DO_STATS 8-bit Flag: If non-zero, update stats next frame. ;; ;; B0_TICK 8-bit Count: Ignore bullet 0 collisions while != 0. ;; ;; B1_TICK 8-bit Count: Ignore bullet 1 collisions while != 0. ;; ;; AVL_TICK 8-bit Count: Apply angular vel. to turrets every N ticks ;; ;; BULx_XVL 16-bit X velocity (8.8) of bullet ;; ;; BULx_YVL 16-bit Y velocity (8.8) of bullet ;; ;; MOB_DIS 16-bit MOB collision table dispatch pointer (from MOB_LL) ;; ;; MOB_IGN 16-bit MOB collision ignore table pointer (from MOB_LL) ;; ;; ;; ;; ------------------------------------------------------------------------ ;; ;; EXTERNAL STRUCTURES REFERENCED BY THIS MODULE ;; ;; ;; ;; MOB_PIC MOB picture table (from MOB_LL) ;; ;; MOB_ATR MOB attribute table (from MOB_LL) ;; ;; MOB_XYP MOB X/Y position table (from MOB_LL) ;; ;; GFX.xxx Graphics picture numbers associated with game elements ;; ;; ATR.xxx MOB attribute numbers associated w/ game elements ;; ;; MNUM.xxx MOB numbers assigned to individual game elements ;; ;; SINCOS Sine/Cosine table for initial bullet velocity ;; ;; TURTBL Turret picture-number lookup table ;; ;; BULOFS Bullet pixel offset by turret angle lookup table ;; ;; FACE MOB attribute lookup for tank facing left/right ;; ;; ;; ;; ------------------------------------------------------------------------ ;; ;; FUNCTIONS DEFINED IN THIS MODULE ;; ;; ;; ;; INIT_TANK Initialize the two tanks ;; ;; MOVE_TANK0 Move tank 0 by the amount in R2 ;; ;; MOVE_TANK1 Move tank 1 by the amount in R2 ;; ;; MOVE_TUR Move turret for tank in R0 by amount in R2 ;; ;; UPD_TANKS Do per-frame updates for tanks (movement etc.) ;; ;; UPD_BULLET Do per-frame updates for bullets (movement etc.) ;; ;; HIT_BULLET Handle bullet collisions ;; ;; FIRE_BULLET Make a bullet airborne for a tank. ;; ;; ======================================================================== ;; ;; ======================================================================== ;; ;; INIT_TANK -- Initializes the two tanks. ;; ;; ======================================================================== ;; INIT_TANK PROC PSHR R5 MVII #DISPATCH, R0 MVOD R0, MOB_DIS MVII #IGNORE, R0 MVOD R0, MOB_IGN ; MOBs 0..2 are first tank ; tank body CALL MOB_CREATE DECLE MNUM.t0_body DECLE pack(87, 10) DECLE ATR.r_tbody DECLE pack(GFX.tbody+1, GFX.tbody) ; tank turret CALL MOB_CREATE DECLE MNUM.t0_tur DECLE pack(87, 10) DECLE ATR.r_tur DECLE pack(GFX.turbot, GFX.tur0) ; tank tread CALL MOB_CREATE DECLE MNUM.t0_tread DECLE pack(87, 10) DECLE ATR.r_tread DECLE pack(GFX.none, GFX.tread1) ; MOBs 3..5 are first tank ; tank body CALL MOB_CREATE DECLE MNUM.t1_body DECLE pack(87, 153) DECLE ATR.l_tbody DECLE pack(GFX.tbody+1, GFX.tbody) ; tank turret CALL MOB_CREATE DECLE MNUM.t1_tur DECLE pack(87, 153) DECLE ATR.l_tur DECLE pack(GFX.turbot, GFX.tur0) ; tank tread CALL MOB_CREATE DECLE MNUM.t1_tread DECLE pack(87, 153) DECLE ATR.l_tread DECLE pack(GFX.none, GFX.tread0) ;; Set up the other tank variables CLRR R0 MVO R0, TNK0_ANG ; turret faces hard right MVO R0, TNK0_AVL ; turret isn't moving MVO R0, TNK1_AVL ; turret isn't moving MVII #18, R0 MVO R0, TNK1_ANG ; turret faces hard left MVII #5, R0 MVO R0, TNK0_POW ; initial firing strength of 5 MVO R0, TNK1_POW ; initial firing strength of 5 PULR PC ENDP ;; ======================================================================== ;; ;; MOVE_TANK0 -- Move tank 0 left or right by amount in R2. ;; ;; ======================================================================== ;; MOVE_TANK0 PROC PSHR R5 CALL MOB_MOVE_M.0 ; DX is already in R2 DECLE $0000 ; make DY = 0. DECLE $07 ; Tank #0 is MOBs 0..2 MVI XYPAddr(MNUM.t0, x_hi), R1 ; tank 0's X position CMPI #8, R1 BGT @@ok_left CLRR R1 MVO R1, TNK0_MOV ; halt the tank CALL MOB_GOTO_M ; DECLE $08E0 ; clamp left border, rounded up DECLE 87*256 ; DECLE $07 ; Tank #0 is MOBs 0..2 B @@ok_right @@ok_left: CMPI #151, R1 BLT @@ok_right CLRR R1 MVO R1, TNK0_MOV ; halt the tank CALL MOB_GOTO_M ; DECLE $9700 ; clamp exactly to right border DECLE 87*256 ; DECLE $07 ; Tank #0 is MOBs 0..2 @@ok_right: ; Compute tread alignment given final resting position of tank0 MVI XYPAddr(MNUM.t0, x_hi), R1 ; tank 0's X position MOD3 R1, R3 ; R1 = R1 MOD 3, using R0 as temp ; figure out what way we're facing so we can negate the MOD MVI AtrAddr(MNUM.t0_tread), R2 ; tank 0's tread attribute CMPI #ATR.r_tread,R2 ; is it right-facing? BEQ @@right ; yes: Don't flip NEGR R1 ; \ no: Flip in such a way BEQ @@ok ; |- that the flipped tread ADDI #3, R1 ; / aligns to the non-flipped @@ok: @@right: ; store new picture number for tread, one of tread0 thru tread2. ADDI #GFX.tread0+$80, R1 MVO R1, PicAddr(MNUM.t0_tread, top) PULR R5 B FLG_STICSH ENDP ;; ======================================================================== ;; ;; MOVE_TANK1 -- Move tank 1 left or right by amount in R2. ;; ;; ======================================================================== ;; MOVE_TANK1 PROC PSHR R5 CALL MOB_MOVE_M.0 ; DX is already in R2 DECLE $0000 ; make DY = 0. DECLE $38 ; Tank #1 is MOBs 3..5 MVI XYPAddr(MNUM.t1, x_hi), R1 ; tank 1's X position CMPI #159, R1 BLT @@ok_right CLRR R1 MVO R1, TNK1_MOV ; halt the tank CALL MOB_GOTO_M ; DECLE 159*256 ; clamp exactly to right border DECLE 87*256 ; DECLE $38 ; Tank #1 is MOBs 3..5 B @@ok_left @@ok_right: CMPI #16, R1 BGT @@ok_left CLRR R1 MVO R1, TNK1_MOV ; halt the tank CALL MOB_GOTO_M ; DECLE $10E0 ; clamp exactly to left border DECLE 87*256 ; DECLE $38 ; Tank #1 is MOBs 3..5 @@ok_left: ; Compute tread alignment given final resting position of tank1 MVI XYPAddr(MNUM.t1, x_hi), R1 ; tank 1's X position MOD3 R1, R3 ; R1 = R1 MOD 3, using R0 as temp ; figure out what way we're facing so we can negate the MOD MVI AtrAddr(MNUM.t1_tread), R2 ; tank 1's tread attribute CMPI #ATR.r_tread,R2 ; is it right-facing? BEQ @@right ; yes: Don't flip NEGR R1 ; \ no: Flip in such a way BEQ @@ok ; |- that the flipped tread ADDI #3, R1 ; / aligns to the non-flipped @@ok: @@right: ; store new picture number for tread, one of tread0 thru tread2. ADDI #GFX.tread0+$80, R1 MVO R1, PicAddr(MNUM.t1_tread, top) PULR R5 B FLG_STICSH ENDP ;; ======================================================================== ;; ;; MOVE_TUR -- Move a turret CW/CCW by amount in R2. Tank # in R0. ;; ;; ======================================================================== ;; MOVE_TUR PROC PSHR R5 MVII #1, R1 MVO R1, DO_STATS MVII #TNK0_ANG, R1 ;\__ Index to requested tank ADDR R0, R1 ;/ NEGR R2 ; CW is negative angle ADD@ R1, R2 ; Add turret rotation to current BGE @@ok_lo ; don't let it go negative CLRR R2 ; clamp to 0 @@ok_lo: CMPI #18, R2 ; don't let it go above 180 BLE @@ok_hi ; MVII #18, R2 ; clamp to 180 @@ok_hi: MVO@ R2, R1 ; store new turret position MVII #AtrAddr(MNUM.t0), R5 ; might need to face tank other way MVII #PicAddr(MNUM.t0_tur,top), R3 TSTR R0 BEQ @@tank0 MVII #AtrAddr(MNUM.t1), R5 ; might need to face tank other way MVII #PicAddr(MNUM.t1_tur,top), R3 @@tank0: ADDI #TURTBL, R2 ; Look up required turret angle MVI@ R2, R2 SARC R2, 2 MVO@ R2, R3 ; store turret picture # for tank BOV @@no_face MVII #FACE.lft, R4 BC @@face_left MVII #FACE.rgt, R4 @@face_left: REPEAT 3 MVI@ R4, R1 MVO@ R1, R5 ENDR MVII #1, R1 MVII #TNK0_FLP, R2 ADDR R0, R2 MVO@ R1, R2 PULR R5 B FLG_STICSH @@no_face: PULR PC ENDP ;; ======================================================================== ;; ;; UPD_TANKS -- Per-frame updates for tanks. ;; ;; ======================================================================== ;; UPD_TANKS PROC PSHR R5 ;; ------------------------------------------------------------ ;; ;; If the two tanks collide this tick, then the actual vel ;; ;; of both is the average of the two requested velocities. ;; ;; Otherwise, the velocity of each is the requested velocity. ;; ;; ------------------------------------------------------------ ;; MVI TNK0_VEL, R0 ; get tank 0's desired vel MVI TNK1_VEL, R1 ; get tank 1's desired vel MVII #XYPAddr(MNUM.t1, x_lo), R4 ;\ SDBD ; | MVI@ R4, R2 ; |_ Find the distance between MVII #XYPAddr(MNUM.t0, x_lo), R4 ; | the two tanks. SDBD ; | SUB@ R4, R2 ;/ CMPI #$0801, R2 ; Are they in contact? BC @@no_hit ; only do this if they're moving towards each other. this isn't ; a towing service. SWAP R0 ; |-- skip out if tank 0 TSTR R0 BMI @@no_hit0 ;/ is moving left SWAP R1 ; |-- skip out if tank 1 TSTR R1 BEQ @@hit ; | is moving right BPL @@no_hit1 ;/ @@hit: ADDR R1, R0 ;\ SAR R0, 1 ; | They're in contact, so SWAP R0, 1 ; |_ each has an actual vel. MVO R0, TNK0_MOV ; | that's the average of the MVO R0, TNK1_MOV ; | two desired velocities. B @@done_vel ;/ @@no_hit1: SWAP R1 @@no_hit0: SWAP R0 @@no_hit: MVO R0, TNK0_MOV MVO R1, TNK1_MOV @@done_vel: ;; ------------------------------------------------------------ ;; ;; Only do turret updates every few frames. ;; ;; ------------------------------------------------------------ ;; MVI AVL_TICK, R0 DECR R0 BPL @@no_tur_0 ;; ------------------------------------------------------------ ;; ;; Update Tank 0's turret position based on angular velocity. ;; ;; ------------------------------------------------------------ ;; MVI TNK0_AVL, R2 DECR R2 BMI @@no_tur_0 BNEQ @@tur_0_cw DECR R2 @@tur_0_cw: CLRR R0 CALL MOVE_TUR @@no_tur_0: ;; ------------------------------------------------------------ ;; ;; Update Tank 0's position based on its velocity. ;; ;; ------------------------------------------------------------ ;; MVI TNK0_MOV, R2 SWAP R2 CMP TNK0_FLP, R2 ; forces 'MOVE' call if tank flips l/r BEQ @@no_move_0 MVO R2, TNK0_FLP SAR R2, 2 SAR R2, 1 CALL MOVE_TANK0 @@no_move_0: MVI AVL_TICK, R0 DECR R0 BPL @@no_tur_1 ;; ------------------------------------------------------------ ;; ;; Update Tank 1's turret position based on angular velocity. ;; ;; ------------------------------------------------------------ ;; MVI TNK1_AVL, R2 DECR R2 BMI @@no_tur_1 BNEQ @@tur_1_cw DECR R2 @@tur_1_cw: MVII #1, R0 CALL MOVE_TUR @@no_tur_1: ;; ------------------------------------------------------------ ;; ;; Update Tank 1's position based on its velocity. ;; ;; ------------------------------------------------------------ ;; MVI TNK1_MOV, R2 SWAP R2 CMP TNK1_FLP, R2 ; forces 'MOVE' call if tank flips l/r BEQ @@no_move_1 MVO R2, TNK1_FLP SAR R2, 2 SAR R2, 1 CALL MOVE_TANK1 @@no_move_1: MVI AVL_TICK, R0 DECR R0 BPL @@tick_ok MVII #3, R0 @@tick_ok: MVO R0, AVL_TICK PULR PC ENDP ;; ======================================================================== ;; ;; UPD_BULLET -- Update bullet positions, etc. ;; ;; ======================================================================== ;; UPD_BULLET PROC PSHR R5 ;; ------------------------------------------------------------ ;; ;; Update the "bullet no-hit" timers. ;; ;; ------------------------------------------------------------ ;; MVI B0_TICK, R0 DECR R0 BMI @@b0_live MVO R0, B0_TICK @@b0_live: MVI B1_TICK, R0 DECR R0 BMI @@b1_live MVO R0, B1_TICK @@b1_live: ;; ------------------------------------------------------------ ;; ;; Update bullet 0. ;; ;; ------------------------------------------------------------ ;; MVI AtrAddr(MNUM.b0),R0 ; Take a look at bullet 0's MOB CMPI #ATR.bullet,R0 ; Is this (still) a bullet? BNEQ @@done_b0 ; no? skip it. ; make sure bullet 0 doesn't go below ground level. If it's ; on the ground, just leave it there MVI XYPAddr(MNUM.b0,y_hi), R0 CMPI #88, R0 BGE @@done_b0 ; accelerate bullet 0 by gravity and then move it. MVI BUL0_YVL, R3 ;\ ADDI #GRAVITY, R3 ; |- Accelerate it by gravity CMPI #$00FF, R3 ;/ BLE @@b0v_ok ; MVII #$00FF, R3 ; clamp y velocity to $00.FF @@b0v_ok: MVO R3, BUL0_YVL ; store updated y velocity MVI BUL0_XVL, R2 ; get bullet 0's x velocity CALL MOB_MOVE.1 ; move bullet 0 DECLE MNUM.b0 MVI XYPAddr(MNUM.b0,x_hi), R0 ;\ CMPI #1, R0 ; |_ destroy bullet if it BLT @@kill_b0 ; | goes offscreen CMPI #159, R0 ;/ BLE @@done_b0 @@kill_b0: CALL MOB_DESTROY DECLE MNUM.b0 @@done_b0: ;; ------------------------------------------------------------ ;; ;; Update bullet 1. ;; ;; ------------------------------------------------------------ ;; MVI AtrAddr(MNUM.b1),R0 ; Take a look at bullet 1's MOB CMPI #ATR.bullet,R0 ; Is this (still) a bullet? BNEQ @@done_b1 ; no? skip it. ; make sure bullet 1 doesn't go below ground level. If it's ; on the ground, just leave it there MVI XYPAddr(MNUM.b1,y_hi), R0 CMPI #88, R0 BGE @@done_b1 ; accelerate bullet 1 by gravity and then move it. MVI BUL1_YVL, R3 ;\ ADDI #GRAVITY, R3 ; |- Accelerate it by gravity CMPI #$00FF, R3 ;/ BLE @@b1v_ok ; MVII #$00FF, R3 ; clamp y velocity to $00.FF @@b1v_ok: MVO R3, BUL1_YVL ; store updated y velocity MVI BUL1_XVL, R2 ; get bullet 1's x velocity CALL MOB_MOVE.1 ; move bullet 1 DECLE MNUM.b1 MVI XYPAddr(MNUM.b1,x_hi), R0 ;\ CMPI #1, R0 ; |_ destroy bullet if it BLT @@kill_b1 ; | goes offscreen CMPI #159, R0 ;/ BLE @@done_b1 @@kill_b1: CALL MOB_DESTROY DECLE MNUM.b1 @@done_b1: ;; ------------------------------------------------------------ ;; ;; Update bullet 0's explosion, if it's exploding. ;; ;; ------------------------------------------------------------ ;; MVI PicAddr(MNUM.b0,top),R0 ; Take a look at bullet 0's MOB CMPI #GFX.exp0, R0 ;\ BLT @@done_e0 ; |_ is it one of the explosion CMPI #GFX.exp7, R0 ; | frames? BGT @@done_e0 ;/ BNEQ @@next_e0 ; Is it one of the first 7? CALL MOB_DESTROY ;\__ take down the animation DECLE MNUM.b0 ;/ on its last frame B @@done_e0 @@next_e0: INCR R0 ;\ ADDI #$80, R0 ; |- advance the explosion anim MVO R0, PicAddr(MNUM.b0,top);/ by one frame. @@done_e0: ;; ------------------------------------------------------------ ;; ;; Update bullet 1's explosion, if it's exploding. ;; ;; ------------------------------------------------------------ ;; MVI PicAddr(MNUM.b1,top),R0 ; Take a look at bullet 1's MOB CMPI #GFX.exp0, R0 ;\ BLT @@done_e1 ; |_ is it one of the explosion CMPI #GFX.exp7, R0 ; | frames? BGT @@done_e1 ;/ BNEQ @@next_e1 ; Is it one of the first 7? CALL MOB_DESTROY ;\__ take down the animation DECLE MNUM.b1 ;/ on its last frame B @@done_e1 @@next_e1: INCR R0 ;\ ADDI #$80, R0 ; |- advance the explosion anim MVO R0, PicAddr(MNUM.b1,top);/ by one frame. @@done_e1: PULR R5 B FLG_STICSH ENDP ;; ======================================================================== ;; ;; HIT_BULLET -- Handle bullet collisions w/ tanks, ground, walls. ;; ;; ======================================================================== ;; HIT_BULLET PROC @@0: PSHR R5 ;; ------------------------------------------------------------ ;; ;; Filter out collisions during first tick or so of bullet's ;; ;; life, since it might strike the firing tank itself on the ;; ;; way out if the tank is moving. We want to ignore that. ;; ;; ------------------------------------------------------------ ;; CLRR R0 CMP B0_TICK, R0 BNEQ @@leave ;; ------------------------------------------------------------ ;; ;; Convert bullets into explosions. ;; ;; ------------------------------------------------------------ ;; MVI PicAddr(MNUM.b0, top), R0 ;\_ don't destroy explosions CMPI #GFX.bullet, R0 ;/ BNEQ @@already_exploding ; Make this an explosion. MVII #GFX.exp0, R0 MVO R0, PicAddr(MNUM.b0, top) MVII #ATR.explode, R0 MVO R0, AtrAddr(MNUM.b0) ; Slide it over 3 pixels to center it MVI XYPAddr(MNUM.b0, x_hi), R0 ADDI #3, R0 MVO R0, XYPAddr(MNUM.b0, x_hi) CLRR R0 MVO R0, BUL0_XVL MVO R0, BUL0_YVL B @@already_exploding @@1: PSHR R5 ;; ------------------------------------------------------------ ;; ;; Filter out collisions during first tick or so of bullet's ;; ;; life, since it might strike the firing tank itself on the ;; ;; way out if the tank is moving. We want to ignore that. ;; ;; ------------------------------------------------------------ ;; CLRR R0 CMP B1_TICK, R0 BNEQ @@leave ;; ------------------------------------------------------------ ;; ;; Convert bullets into explosions. ;; ;; ------------------------------------------------------------ ;; MVI PicAddr(MNUM.b1, top), R0 ;\_ don't destroy explosions CMPI #GFX.bullet, R0 ;/ BNEQ @@already_exploding ; Make this an explosion. MVII #GFX.exp0, R0 MVO R0, PicAddr(MNUM.b1, top) MVII #ATR.explode, R0 MVO R0, AtrAddr(MNUM.b1) ; Slide it over 4 pixels to center it MVI XYPAddr(MNUM.b1, x_hi), R0 ADDI #4, R0 MVO R0, XYPAddr(MNUM.b1, x_hi) CLRR R0 MVO R0, BUL1_XVL MVO R0, BUL1_YVL @@already_exploding: ;; ------------------------------------------------------------ ;; ;; Check to see whether this bullet/explosion hit one or both ;; ;; tanks. For every frame that an explosion hits one tank, ;; ;; the other tank gets a point. ;; ;; ------------------------------------------------------------ ;; MOVR R2, R3 ; save explosion mask ANDI #$07, R2 ; did we hit tank 0? BEQ @@no_tank_0 MVI TNK1_PTS, R0 INCR R0 BEQ @@no_tank_0 ; prevent overflow MVO R0, TNK1_PTS MVII #1, R1 MVO R1, DO_STATS @@no_tank_0: ANDI #$38, R3 ; did we hit tank 0? BEQ @@no_tank_1 MVI TNK0_PTS, R0 INCR R0 BEQ @@no_tank_1 ; prevent overflow MVO R0, TNK0_PTS MVII #1, R1 MVO R1, DO_STATS @@no_tank_1: @@leave: PULR PC ENDP ;; ======================================================================== ;; ;; FIRE_BULLET -- Fires a bullet for the tank in R0. ;; ;; ======================================================================== ;; FIRE_BULLET PROC PSHR R5 ;; ------------------------------------------------------------ ;; ;; Check to see if this tank already has a bullet in the air. ;; ;; ------------------------------------------------------------ ;; MVII #AtrAddr(MNUM.b0),R1;\_ Point to this tank's bullet ADDR R0, R1 ;/ attribute MVI@ R1, R1 ; get the attribute for this bullet TSTR R1 ;\__ if it's non-zero, it's either BNEQ @@leave ;/ a bullet or explosion. Leave. MVII #4, R3 ; Initial value for "no-hit" timer MVII #ATR.l_tur, R1 ; will need to determine tank's dir. TSTR R0 ;\__ load parameters for appropriate BEQ @@t0 ;/ tank @@t1: MVO R3, B1_TICK ; set bullet 1's no-hit timer MVI TNK1_ANG, R3 ; get tank 1's firing angle CMP AtrAddr(MNUM.t1_tur), R1 ;\ add 1 if facing left BNEQ @@t1_rgt ; |- to distinguish 90 deg INCR R3 ;/ left from 90 deg right @@t1_rgt: MVII #XYPAddr(MNUM.t1,x_hi), R1 ; point R1 to tank 1's X coord B @@tdone @@t0: MVO R3, B0_TICK ; set bullet 0's no-hit timer MVI TNK0_ANG, R3 ; get tank 0's firing angle CMP AtrAddr(MNUM.t0_tur), R1 ;\ add 1 if facing left BNEQ @@t0_rgt ; |- to distinguish 90 deg INCR R3 ;/ left from 90 deg right @@t0_rgt: MVII #XYPAddr(MNUM.t0,x_hi), R1 ; point R1 to tank 0's X coord @@tdone: ;; ------------------------------------------------------------ ;; ;; Compute the initial position for the bullet based on tank's ;; ;; position and turret angle. R3 has turret angle. ;; ;; ------------------------------------------------------------ ;; MVI@ R1, R2 ; get tank's X position into lower byte ADDI #87*256, R2 ; Set Y coordinate to base of tank ADDI #BULOFS, R3 ; point to packed X/Y offset for bullet SUB@ R3, R2 ; move the bullet up/left as necessary PSHR R0 ; save the tank # ;; ------------------------------------------------------------ ;; ;; Create the MOB for the bullet. ;; ;; ------------------------------------------------------------ ;; MVII #MNUM.b0, R1 ;\__ Pick the bullet based on tank# ADDR R0, R1 ;/ CALL MOB_CREATE.2 ;\ DECLE ATR.bullet ; |- make the bullet DECLE pack(GFX.none, GFX.bullet) ;/ PULR R0 ; restore tank # from stack ;; ------------------------------------------------------------ ;; ;; Setup the X/Y velocity for the bullet. We use these eqs: ;; ;; x_vel = (fire_power + 2) * cos(angle) / 4 + tank_x_vel ;; ;; y_vel = (fire_power + 2) * sin(angle) / 4 ;; ;; ------------------------------------------------------------ ;; MVII #BUL0_XVL, R4 ;\ ADDR R0, R4 ; |- point to the correct bullet's ADDR R0, R4 ;/ velocity MVII #SINCOS, R5 ;\ MVII #TNK0_ANG, R2 ; | ADDR R0, R2 ; |- Index into Sine/Cosine table ADD@ R2, R5 ; | based on this tank's turret angle ADD@ R2, R5 ;/ ADDI #TNK0_POW-TNK0_ANG, R2 ;\__ Get tank's firing power MVI@ R2, R1 ;/ into R1. ADDI #2, R1 ; Add 2, since '1' is pretty wimpy SUBI #TNK0_POW-TNK0_MOV, R2 ;\ MVI@ R2, R2 ; |_ Initialize bullet velocity SWAP R2 ; | to this tank's horizontal SAR R2, 1 ;/ velocity * 4. CLRR R3 ; initialize vertical vel to 0. @@mul_loop ; Multiply sine/cosine by tank's firing power. ADD@ R5, R2 ; Add cosine to horizontal ADD@ R5, R3 ; Add sine to vertical SUBI #2, R5 ; keep pointing to to same sine/cosine DECR R1 ;\__ multiply iteratively BNEQ @@mul_loop ;/ SAR R2, 2 ; Divide X velocity by 4 SAR R3, 2 ; Divide Y velocity by 4 MVO@ R2, R4 ; store X velocity MVO@ R3, R4 ; store Y velocity @@leave: PULR PC ENDP ;* ======================================================================== *; ;* This program is free software; you can redistribute it and/or modify *; ;* it under the terms of the GNU General Public License as published by *; ;* the Free Software Foundation; either version 2 of the License, or *; ;* (at your option) any later version. *; ;* *; ;* This program is distributed in the hope that it will be useful, *; ;* but WITHOUT ANY WARRANTY; without even the implied warranty of *; ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *; ;* General Public License for more details. *; ;* *; ;* You should have received a copy of the GNU General Public License *; ;* along with this program; if not, write to the Free Software *; ;* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *; ;* ======================================================================== *; ;* Copyright (c) 2003, Joseph Zbiciak *; ;* ======================================================================== *;