From aa6c37eb6145a17b598e1778ef582f2a5b4dd248 Mon Sep 17 00:00:00 2001 From: Pecusx Date: Wed, 31 Aug 2022 20:35:20 +0200 Subject: [PATCH] AI optimizations and more (81b loss :( ) --- MANUAL_EN.md | 10 ++++---- MANUAL_PL.md | 10 ++++---- ai.asm | 62 +++++++++++++++++++++++++++++++++++++------------- constants.asm | 2 +- scorch.xex | Bin 50446 -> 50527 bytes 5 files changed, 57 insertions(+), 27 deletions(-) diff --git a/MANUAL_EN.md b/MANUAL_EN.md index 137a0ab..951b003 100644 --- a/MANUAL_EN.md +++ b/MANUAL_EN.md @@ -209,11 +209,11 @@ The game has 8 difficulty levels of computer-controlled opponents. Or actually 7 ** **Tosser** - When attacking, he acts exactly like **Poolshark** however, he may have a "better" weapon inventory due to a different purchase tactic. He always activates the best defensive weapon he has before shooting. And just like **Poolshark** he uses **Battery** and **White Flag**. At the beginning of the round, he assesses how much money he has and depending on that, he makes (money/5100) attempts to buy defensive weapons and then checks again how much money he has left and makes (money/1250) attempts to buy offensive weapons. -** **Chooser** - Takes as a target the weakest opponent (with the least amount of energy) and aims very precisely, but before the shot the energy of the shot is modified by the parameter of luck :) , that is, despite the precise aiming it does not always hit. He shoots with the best weapon he has unless low energy is required (the target is close). Then he changes his weapon to **Baby Missile** to avoid hitting himself. He always activates the best defensive weapon he has before shooting and, like **Poolshark**, uses **Battery** and **White Flag**. He purchases just like **Tosser**. +** **Chooser** - Takes as a target the weakest opponent (with the least amount of energy) and aims very precisely, but before the shot the energy of the shot is modified by the parameter of luck :) , that is, despite the precise aiming it does not always hit. He shoots with the best weapon he has unless the target is close. Then he changes his weapon to **Baby Missile** to avoid hitting himself. He always activates the best defensive weapon he has before shooting and, like **Poolshark**, uses **Battery** and **White Flag**. He purchases just like **Tosser**. * **Spoiler** - He shoots exactly like **Chooser** except that he has more luck :) , which means that even if he doesn't hit the target of his choice, it can be a more precise shot than **Chooser**. He uses defensive weapons exactly like **Chooser**. At the beginning of the round, he assesses how much money he has and depending on that, he makes (money/5100) attempts to buy defensive weapons and then checks again how much money he has left and makes (money/320) attempts to buy offensive weapons. When buying defensive weapons, he buys only strong and precise weapons - that is, weapons that won't accidentally hurt him. -** **Cyborg** - Takes aim at the weakest opponent (with the least amount of energy) but prefers human-controlled opponents. Aims very accurately and in the vast majority of cases hits on the first shot. He fires the shot with the best weapon he has unless low energy is required (the target is close). Then he changes his weapon to **Baby Missile** to avoid hitting himself. He uses defensive weapons exactly like **Chooser**. He shops exactly like **Spoiler**. +** **Cyborg** - Takes aim at the weakest opponent (with the least amount of energy) but prefers human-controlled opponents. Aims very accurately and in the vast majority of cases hits on the first shot. He fires the shot with the best weapon he has unless the target is close. Then he changes his weapon to **Baby Missile** to avoid hitting himself. He uses defensive weapons exactly like **Chooser**. He shops exactly like **Spoiler**. * **Unknown** - Before firing each shot, he randomly chooses a course of action from **Poolshark** to **Cyborg** and applies his tactics. However, the tactics of weapon purchases are always identical to **Tosser**. @@ -241,9 +241,9 @@ Table of weapons purchased by: **Spoiler** and **Cyborg**. | Offensive weapons | Defensive weapons | | --- | --- | -| Baby Nuke | Battery | -| Nuke | Strong Parachute | -| Death's Head | Mag Deflector | +| Missile | Battery | +| Baby Nuke | Strong Parachute | +| Nuke | Mag Deflector | | Hot Napalm | Heavy Shield | | | Force Shield | | | Bouncy Castle | diff --git a/MANUAL_PL.md b/MANUAL_PL.md index e66fe67..adff1fa 100644 --- a/MANUAL_PL.md +++ b/MANUAL_PL.md @@ -204,11 +204,11 @@ Gra posiada 8 poziomów trudności przeciwników sterowanych przez komputer. A w * **Tosser** - Atakując działa dokładnie tak jak **Poolshark** jednak może posiadać "lepszy" zasób broni dzięki innej taktyce zakupów. Zawsze przed strzałem aktywuje najlepszą posiadaną broń defensywną. i tak jak **Poolshark** stosuje **Battery** i **White Flag**. Na początku rundy ocenia ile ma pieniędzy i w zależności od tego podejmuje (pieniądze/5100) prób zakupu broni defensywnych a następnie jeszcze raz sprawdza ile pieniędzy mu zostało i podejmuje (pieniądze/1250) prób zakupu broni ofensywnych. -* **Chooser** - Obiera sobie za cel najsłabszego przeciwnika (o najmniejszym zasobie energii) i celuje bardzo dokładnie, jednak przed samym strzałem energia strzału modyfikowana jest o parametr szczęścia :) , czyli mimo precyzyjnego wycelowania nie zawsze trafia. Strzał oddaje najlepszą posiadaną bronią chyba że wymagana jest małą energia (cel jest blisko). Wtedy zmienia broń na **Baby Missile** by unikać trafienia samego siebie. Zawsze przed strzałem aktywuje najlepszą posiadaną broń defensywną i tak jak **Poolshark** stosuje **Battery** i **White Flag**. Zakupów dokonuje tak samo jak **Tosser**. +* **Chooser** - Obiera sobie za cel najsłabszego przeciwnika (o najmniejszym zasobie energii) i celuje bardzo dokładnie, jednak przed samym strzałem energia strzału modyfikowana jest o parametr szczęścia :) , czyli mimo precyzyjnego wycelowania nie zawsze trafia. Strzał oddaje najlepszą posiadaną bronią chyba że cel jest blisko. Wtedy zmienia broń na **Baby Missile** by unikać trafienia samego siebie. Zawsze przed strzałem aktywuje najlepszą posiadaną broń defensywną i tak jak **Poolshark** stosuje **Battery** i **White Flag**. Zakupów dokonuje tak samo jak **Tosser**. * **Spoiler** - Strzela dokładnie tak jak **Chooser** tyle, że ma więcej szczęścia :) , co oznacza że nawet jeśli nie trafi w wybrany cel, to może być to strzał precyzyjniejszy niż **Chooser**. Broni defensywnych używa dokładnie tak jak **Chooser**. Na początku rundy ocenia ile ma pieniędzy i w zależności od tego podejmuje (pieniądze/5100) prób zakupu broni defensywnych a następnie jeszcze raz sprawdza ile pieniędzy mu zostało i podejmuje (pieniądze/320) prób zakupu broni ofensywnych. Przy zakupie broni defensywnych kupuje tylko bronie silne i precyzyjne - czyli takie, które nie zrobią mu przypadkiem krzywdy. -* **Cyborg** - Obiera sobie za cel najsłabszego przeciwnika (o najmniejszym zasobie energii) lecz preferuje przeciwników sterowanych przez człowieka. Celuje bardzo dokładnie i w zdecydowanej większości przypadków trafia za pierwszym strzałem. Strzał oddaje najlepszą posiadaną bronią chyba że wymagana jest małą energia (cel jest blisko). Wtedy zmienia broń na **Baby Missile** by unikać trafienia samego siebie. Broni defensywnych używa dokładnie tak jak **Chooser**. Zakupy robi dokładnie tak jak **Spoiler** +* **Cyborg** - Obiera sobie za cel najsłabszego przeciwnika (o najmniejszym zasobie energii) lecz preferuje przeciwników sterowanych przez człowieka. Celuje bardzo dokładnie i w zdecydowanej większości przypadków trafia za pierwszym strzałem. Strzał oddaje najlepszą posiadaną bronią chyba że cel jest blisko. Wtedy zmienia broń na **Baby Missile** by unikać trafienia samego siebie. Broni defensywnych używa dokładnie tak jak **Chooser**. Zakupy robi dokładnie tak jak **Spoiler** * **Unknown** - Przed oddaniem każdego strzału losowo wybiera sposób działania od **Poolsharka** do **Cyborga** i stosuje jego taktykę. Taktyka zakupów broni jest jednak zawsze identyczna jak **Tosser** @@ -236,9 +236,9 @@ Tabela broni kupowanych przez: **Spoiler** i **Cyborg** | bronie ofensywne | bronie defensywne | | --- | --- | -| Baby Nuke | Battery | -| Nuke | Strong Parachute | -| Death's Head | Mag Deflector | +| Missile | Battery | +| Baby Nuke | Strong Parachute | +| Nuke | Mag Deflector | | Hot Napalm | Heavy Shield | | | Force Shield | | | Bouncy Castle | diff --git a/ai.asm b/ai.asm index 0c464db..e65a98d 100644 --- a/ai.asm +++ b/ai.asm @@ -155,7 +155,6 @@ endo ; choose the best weapon - ldy #last_offensive_____ ;the last weapon to choose +1 jsr ChooseBestOffensive rts .endp @@ -202,7 +201,6 @@ endo ; choose the best weapon - ldy #ind_Laser__________ ;the last offensive weapon to choose +1 jsr ChooseBestOffensive rts @@ -317,7 +315,6 @@ NoUseDefensive jsr TakeAim ; direction still in A (0 - left, >0 - right) ; choose the best weapon - ldy #ind_LeapFrog_______ ;the last offensive weapon to use +1 jsr ChooseBestOffensive ; randomizing force +-100 @@ -327,9 +324,10 @@ NoUseDefensive NotNegativeEnergy adw Force #100 RandBoundaryHigh jsr RandomizeForce - lda ForceTableH,x - bne HighForce - ; if Force lower than 256 - set weapon to Baby Missile (for security :) ) + ; if target distance lower than 24 - set weapon to Baby Missile (for security :) + jsr GetDistance + cpw temp2 #24 + bcs HighForce lda #ind_Baby_Missile___ sta ActiveWeapon,x HighForce @@ -349,7 +347,6 @@ HighForce jsr TakeAim ; direction still in A (0 - left, >0 - right) ; choose the best weapon - ldy #ind_LeapFrog_______ ;the last offensive weapon to use +1 jsr ChooseBestOffensive ; randomizing force +-50 @@ -359,9 +356,10 @@ HighForce NotNegativeEnergy adw Force #50 RandBoundaryHigh jsr RandomizeForce - lda ForceTableH,x - bne HighForce - ; if Force lower than 256 - set weapon to Baby Missile (for security :) ) + ; if target distance lower than 24 - set weapon to Baby Missile (for security :) + jsr GetDistance + cpw temp2 #24 + bcs HighForce lda #ind_Baby_Missile___ sta ActiveWeapon,x HighForce @@ -380,15 +378,17 @@ HighForce jsr TakeAim ; direction still in A (0 - left, >0 - right) ; choose the best weapon - ldy #ind_LeapFrog_______ ;the last offensive weapon to use +1 - jsr ChooseBestOffensive + ldy ind_Nuke___________+1 + jsr ChooseBestOffensive.NotFromAll lda Force sta ForceTableL,x lda Force+1 sta ForceTableH,x - bne HighForce - ; if Force lower than 256 - set weapon to Baby Missile (for security :) ) + ; if target distance lower than 32 - set weapon to Baby Missile (for security :) + jsr GetDistance + cpw temp2 #32 + bcs HighForce lda #ind_Baby_Missile___ sta ActiveWeapon,x HighForce @@ -1014,10 +1014,11 @@ SorryNoPurchase ;---------------------------------------------- .proc ChooseBestOffensive ; choose the best weapon -; Y - the last offensive weapon to use + 1 ; X - TankNr ;---------------------------------------------- - + ldy #last_offensive_____+1 ;the last weapon to choose +1 +NotFromAll +; Y - the last offensive weapon to use + 1 lda TanksWeaponsTableL,x sta temp lda TanksWeaponsTableH,x @@ -1029,4 +1030,33 @@ loop tya sta ActiveWeapon,x rts +.endp +;---------------------------------------------- +.proc GetDistance +; calculates distance from tank X to TargetTankNr(Y) +; result in temp2 +;---------------------------------------------- + ldy TargetTankNr + lda xTanksTableH,x + cmp xTanksTableH,y + bne @+ + lda xTanksTableL,x + cmp xTanksTableL,y +@ bcs YisLower + sec + lda xTanksTableL,y + sbc xTanksTableL,x + sta temp2 + lda xTanksTableH,y + sbc xTanksTableH,x + sta temp2+1 + rts +YisLower + lda xTanksTableL,x + sbc xTanksTableL,y + sta temp2 + lda xTanksTableH,x + sbc xTanksTableH,y + sta temp2+1 + rts .endp \ No newline at end of file diff --git a/constants.asm b/constants.asm index 7a4dd52..2f55d79 100644 --- a/constants.asm +++ b/constants.asm @@ -397,7 +397,7 @@ PurchaseMeTable2 ;weapons good to be purchased by the robot (Cyborg) ;the comment is an index in the tables ; "Baby Missile ","Missile ","Baby Nuke ","Nuke " ; "LeapFrog ","Funky Bomb ","MIRV ","Death's Head " - .by %00110001 + .by %01110000 ; "Napalm ","Hot Napalm ","Tracer ","Smoke Tracer " ; "Baby Roller ","Roller ","Heavy Roller ","Riot Charge " .by %01000000 diff --git a/scorch.xex b/scorch.xex index 91079c2b4b5e31dfd25cba27cfd311bf48a5a57e..a5cf2245350abaf9a2ea3a291ecbfea63f8d1bc5 100644 GIT binary patch delta 10531 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 Xymj?w^H<*8TK#U#e#A8~|*