From c725fd38274572e4238c6fd763e2bb18b3c89623 Mon Sep 17 00:00:00 2001 From: Pecusx Date: Sun, 31 Jul 2022 16:14:01 +0200 Subject: [PATCH] New Cyborg AI --- ai.asm | 338 ++++++++++++++++++++++++++++++++++++++++++-------- scorch.xex | Bin 40783 -> 41187 bytes variables.asm | 3 + weapons.asm | 3 +- 4 files changed, 290 insertions(+), 54 deletions(-) diff --git a/ai.asm b/ai.asm index d6c0828..7496005 100644 --- a/ai.asm +++ b/ai.asm @@ -59,7 +59,7 @@ AIRoutines .word Tosser-1 ;Tosser .word Tosser-1 ;Chooser .word Tosser-1 ;Spoiler - .word Tosser-1 ;Cyborg + .word Cyborg-1 ;Cyborg .word Tosser-1 ;Unknown ;---------------------------------------------- @@ -155,55 +155,7 @@ loop ;---------------------------------------------- .proc Poolshark ; defensives - ; if low energy ten use battery - lda Energy,x - cmp #30 - bcs EnoughEnergy - ; lower than 30 units - check battery - ldy #ind_Battery________ - lda (temp),y ; has address of TanksWeaponsTable - beq NoBatteries - ; we have batteries - use one - clc - sbc #1 - sta (temp),y - lda #99 - sta Energy,x -NoBatteries - ; if very low energy and no battery then use White Flag - lda Energy,x - cmp #5 - bcs EnoughEnergy - ; lower than 5 units - white flag - lda #ind_White_Flag_____ - sta ActiveDefenceWeapon,x -EnoughEnergy - ; use best defensive :) - ; but not allways - randomize 1 3 - cmp #1 - bne NoUseDefensive - ; first check check if any is in use - lda ActiveDefenceWeapon,x - bne DefensiveInUse - ldy #ind_Nuclear_Winter_+1 ;the last defensive weapon -@ - dey - cpy #ind_Battery________ ;first defensive weapon (White Flag nad Battery - never use) - beq NoUseDefensive - lda (temp),y ; has address of TanksWeaponsTable - beq @- - ; decrease in inventory - clc - sbc #1 - sta (temp),y ; has address of TanksWeaponsTable - ; activate defensive weapon - tya ; number of selectet defensive weapon - sta ActiveDefenceWeapon,x - lda DefensiveEnergy,y - sta ShieldEnergy,x -NoUseDefensive -DefensiveInUse + jsr PoolsharkDefensives firstShoot ;find nearest tank neighbour jsr MakeLowResDistances @@ -293,7 +245,68 @@ AngleTable ; 16 bytes ;ba w $348b L$3350 .by 18,26,34,43,50,58,66,74 .endp ;---------------------------------------------- +.proc PoolsharkDefensives + ; defensives + ; if low energy ten use battery + lda Energy,x + cmp #30 + bcs EnoughEnergy + ; lower than 30 units - check battery + ldy #ind_Battery________ + lda (temp),y ; has address of TanksWeaponsTable + beq NoBatteries + ; we have batteries - use one + clc + sbc #1 + sta (temp),y + lda #99 + sta Energy,x +NoBatteries + ; if very low energy and no battery then use White Flag + lda Energy,x + cmp #5 + bcs EnoughEnergy + ; lower than 5 units - white flag + lda #ind_White_Flag_____ + sta ActiveDefenceWeapon,x +EnoughEnergy + ; use best defensive :) + ; but not allways + randomize 1 3 + cmp #1 + bne NoUseDefensive + ; first check check if any is in use + lda ActiveDefenceWeapon,x + bne DefensiveInUse + ldy #ind_Nuclear_Winter_+1 ;the last defensive weapon +@ + dey + cpy #ind_Battery________ ;first defensive weapon (White Flag nad Battery - never use) + beq NoUseDefensive + lda (temp),y ; has address of TanksWeaponsTable + beq @- + ; decrease in inventory + clc + sbc #1 + sta (temp),y ; has address of TanksWeaponsTable + ; activate defensive weapon + tya ; number of selectet defensive weapon + sta ActiveDefenceWeapon,x + lda DefensiveEnergy,y + sta ShieldEnergy,x +NoUseDefensive +DefensiveInUse + rts +.endp +;---------------------------------------------- .proc Tosser + ; use best defensive :) + jsr TosserDefensives + ; Toosser is like Poolshark but allways uses defensives + jmp Poolshark.firstShoot +.endp +;---------------------------------------------- +.proc TosserDefensives ; use best defensive :) ; allways ; first check check if any is in use @@ -317,10 +330,25 @@ AngleTable ; 16 bytes ;ba w $348b L$3350 sta ShieldEnergy,x DefensiveInUse NoUseDefensive - ; Toosser is like Poolshark but allways uses defensives - jmp Poolshark + rts +.endp +;---------------------------------------------- +.proc Cyborg + ; use defensives like Tosser + jsr TosserDefensives + ; now select best target + jsr FindBestTarget1 + sty TargetTankNr + ; aiming + jsr TakeAim ; direction still in A (0 - left, >0 - right) + lda #0 + sta ActiveWeapon,x + lda Force + sta ForceTableL,x + lda Force+1 + sta ForceTableH,x + rts .endp - ;---------------------------------------------- .proc FindBestTarget1 ; find farthest tank neighbour @@ -377,6 +405,210 @@ skipThisPlayer rts .endp ;---------------------------------------------- +.proc TakeAim +; targeting the tank number TargetTankNr (and Y) +; A (and tempor2) - direction from shooting tank (0 - left, >0 - right) +; returns angle and power of shoot tank X (TankNr) +; in the appropriate variables (Angle and Force) +;---------------------------------------------- + ; set initial Angle and Force values + mva #90 NewAngle + lda OptionsTable+2 ; selected gravity + asl + tay + lda AIForceTable,y + sta ForceTableL,x + lda AIForceTable+1,y + sta ForceTableH,x + jsr RandomizeForce.LimitForce + lda ForceTableL,x + sta Force + lda ForceTableH,x + sta Force+1 + ; now we have initial valuses + mva #$ff TestFlightFlag + ; check targeting direction + lda tempor2 + jeq AimingLeft +AimingRight + ; make test Shoot (Flight) + jsr SetStartAndFlight + lda HitFlag + beq NoHitInFirstLoopR ; impossible :) + bmi GroundHitInFirstLoopR +TankHitInFirstLoopR + ; tank hit, but which tank? + ; it's our target or not? + ldy HitFlag + dey + cpy TargetTankNr + beq EndOfFirstLoopR ; it's our target! + ; if it's another tank then check position like ground hit +GroundHitInFirstLoopR + ; checking only x position of hit + ldy TargetTankNr + lda xTanksTableH,y + cmp XHit+1 + bne @+ + lda xTanksTableL,y + cmp XHit +@ + bcc HitOnRightSideOfTargetR + ; continue targeting + sec + lda NewAngle + sbc #5 ; 5 deg to right + cmp #15 + beq EndOfFirstLoopR + sta NewAngle + jmp AimingRight +NoHitInFirstLoopR + ; Angle 5 deg to left and end loop + clc + lda NewAngle + adc #5 + sta NewAngle +HitOnRightSideOfTargetR +EndOfFirstLoopR + mva #5 temp2 ; set counter (5 turns) +SecondLoopR + ; make test Shoot (Flight) + jsr SetStartAndFlight + lda HitFlag + beq NoHitInSecondLoopR ; impossible :) + bmi GroundHitInSecondLoopR +TankHitInSecondLoopR + ; tank hit, but which tank? + ; it's our target or not? + ldy HitFlag + dey + cpy TargetTankNr + beq EndOfSecondLoopR ; it's our target! + ; if it's another tank then check position like ground hit +GroundHitInSecondLoopR + ; checking only x position of hit + ldy TargetTankNr + lda xTanksTableH,y + cmp XHit+1 + bne @+ + lda xTanksTableL,y + cmp XHit +@ + bcs HitOnLeftSideOfTargetR + ; continue targeting + inc NewAngle ; 1 deg to left + dec temp2 ; max 5 turns + beq EndOfSecondLoopR + jmp SecondLoopR +HitOnLeftSideOfTargetR + ; decrease energy (a little) + sbw Energy #5 +NoHitInSecondLoopR + ; Angle 1 deg to right and end loop + dec NewAngle +EndOfSecondLoopR + rts + +AimingLeft + ; make test Shoot (Flight) + jsr SetStartAndFlight + lda HitFlag + beq NoHitInFirstLoopL ; impossible :) + bmi GroundHitInFirstLoopL +TankHitInFirstLoopL + ; tank hit, but which tank? + ; it's our target or not? + ldy HitFlag + dey + cpy TargetTankNr + beq EndOfFirstLoopL ; it's our target! + ; if it's another tank then check position like ground hit +GroundHitInFirstLoopL + ; checking only x position of hit + ldy TargetTankNr + lda xTanksTableH,y + cmp XHit+1 + bne @+ + lda xTanksTableL,y + cmp XHit +@ + bcs HitOnLeftSideOfTargetL + ; continue targeting + clc + lda NewAngle + adc #5 ; 5 deg to left + cmp #(180-15) + beq EndOfFirstLoopL + sta NewAngle + jmp AimingLeft +NoHitInFirstLoopL + ; Angle 5 deg to right and end loop + sec + lda NewAngle + sbc #5 + sta NewAngle +HitOnLeftSideOfTargetL +EndOfFirstLoopL + mva #5 temp2 ; set counter (5 turns) +SecondLoopL + ; make test Shoot (Flight) + jsr SetStartAndFlight + lda HitFlag + beq NoHitInSecondLoopL ; impossible :) + bmi GroundHitInSecondLoopL +TankHitInSecondLoopL + ; tank hit, but which tank? + ; it's our target or not? + ldy HitFlag + dey + cpy TargetTankNr + beq EndOfSecondLoopL ; it's our target! + ; if it's another tank then check position like ground hit +GroundHitInSecondLoopL + ; checking only x position of hit + ldy TargetTankNr + lda xTanksTableH,y + cmp XHit+1 + bne @+ + lda xTanksTableL,y + cmp XHit +@ + bcc HitOnRightSideOfTargetL + ; continue targeting + dec NewAngle ; 1 deg to right + dec temp2 ; max 5 turns + beq EndOfSecondLoopL + jmp SecondLoopL +HitOnRightSideOfTargetL + ; decrease energy (a little) + sbw Energy #5 +NoHitInSecondLoopL + ; Angle 1 deg to left and end loop + inc NewAngle +EndOfSecondLoopL + + rts + +SetStartAndFlight ; set start point (virtual barrel end :) ) and make test flight + ; xtraj+1 and ytraj+1 set + clc + lda xTanksTableL,x + adc #4 + sta xtraj+1 + lda xTanksTableH,x + adc #0 + sta xtraj+2 + sec + lda yTanksTable,x + sbc #4 + sta ytraj+1 + mva #0 ytraj+2 + mva NewAngle Angle + jsr Flight + ldx TankNr + rts +.endp +;---------------------------------------------- .proc PurchaseAI ; ; A - skill of the TankNr ; makes purchase for AI opponents diff --git a/scorch.xex b/scorch.xex index 7225e6e8fcf7ba716794320fd276ceda74a8a6d6..1d3e3c5f0d17e40c37ba6d5fe2eba4f0d93f8a38 100644 GIT binary patch delta 15867 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

~2cKGn#2LFEIwfk?%|1rg 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