diff options
-rw-r--r-- | INSTALL.md | 32 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | Vagrantfile | 59 | ||||
-rw-r--r-- | battle/ai/scoring.asm | 362 | ||||
-rw-r--r-- | main.asm | 38 |
5 files changed, 447 insertions, 46 deletions
diff --git a/INSTALL.md b/INSTALL.md index ca38695af..12fe3aa03 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,3 +1,35 @@ +# Vagrant + +The simplest way to get pokecrystal to compile is to use Vagrant and +VirtualBox. Follow these steps: + +* [Download and install Vagrant](http://www.vagrantup.com/downloads.html) +* Follow the instructions to [download and install VirtualBox](http://docs-v1.vagrantup.com/v1/docs/getting-started/) +* Run these commands: + + vagrant box add pokecrystal http://diyhpl.us/~bryan/irc/pokecrystal/pokecrystal.box + mkdir vagrantbox + cd vagrantbox + vagrant init pokecrystal + vagrant up + vagrant ssh -c "cd /vagrant && git clone git://github.com/kanzure/pokecrystal.git" + vagrant ssh -c "cd /vagrant/pokecrystal && git submodule init && git submodule update" + vagrant ssh + +Running "vagrant ssh" will give you a shell to type commands into for compiling +the source code. The the "virtualbox" directory on the host appears as a shared +folder inside of the guest virtual machine at "/vagrant". + +To build the project, run these commands in the guest (that is, inside "vagrant +ssh"): + + cd /vagrant/pokecrystal + make + +To make the build work you will need to copy baserom.gbc into the "pokecrystal" +directory inside the "virtualbox" directory on the host machine. Eventually +this will not be required. + # Linux Dependencies: @@ -43,7 +43,7 @@ crystal: pokecrystal.gbc clean: rm -f $(roms) $(all_obj) - find -iname '*.tx' -exec rm {} + + find . -iname '*.tx' -exec rm {} + baserom.gbc: ; @echo "Wait! Need baserom.gbc first. Check README and INSTALL for details." && false diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 000000000..ef8ee2f03 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,59 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# TODO: insert scripts to build the box instead of trusting the uploaded +# version. The default should be to build the box when running "vagrant up", +# rather than just downloading a pre-existing box. + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + # All Vagrant configuration is done here. The most common configuration + # options are documented and commented below. For a complete reference, + # please see the online documentation at vagrantup.com. + + # Every Vagrant virtual environment requires a box to build off of. + config.vm.box = "pokecrystal" + config.vm.box_url = "http://diyhpl.us/~bryan/irc/pokecrystal/pokecrystal.box" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + config.vm.network "forwarded_port", guest: 80, host: 8650 + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + config.vm.network "public_network" + + # If true, then any SSH connections made will enable agent forwarding. + # Default value: false + config.ssh.forward_agent = true + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + config.vm.synced_folder "./", "/vagrant" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + config.vm.provider "virtualbox" do |vb| + # Don't boot with headless mode + vb.gui = false + + # Use VBoxManage to customize the VM. For example to change memory: + vb.customize ["modifyvm", :id, "--memory", "1024"] + end +end diff --git a/battle/ai/scoring.asm b/battle/ai/scoring.asm index 5e43470d7..52112faf6 100644 --- a/battle/ai/scoring.asm +++ b/battle/ai/scoring.asm @@ -21,6 +21,9 @@ AI_Basic: ; 38591 ld a, [wEnemyMoveStruct + MOVE_EFFECT] ld c, a +; Dismiss moves with special effects if they are +; useless or not a good choice right now. +; For example, healing moves, weather moves, Dream Eater... push hl push de push bc @@ -30,6 +33,7 @@ AI_Basic: ; 38591 pop hl jr nz, .discourage +; Dismiss status-only moves if the player can't be statused. ld a, [wEnemyMoveStruct + MOVE_EFFECT] push hl push de @@ -47,6 +51,7 @@ AI_Basic: ; 38591 and a jr nz, .discourage +; Dismiss Safeguard if it's already active. ld a, [PlayerScreens] bit SCREENS_SAFEGUARD, a jr z, .checkmove @@ -69,6 +74,10 @@ AI_Basic: ; 38591 AI_Setup: ; 385e0 ; Use stat-modifying moves on turn 1. +; 50% chance to greatly encourage stat-up moves during the first turn of enemy's Pokemon. +; 50% chance to greatly encourage stat-down moves during the first turn of player's Pokemon. +; Almost 90% chance to greatly discourage stat-modifying moves otherwise. + ld hl, Buffer1 - 1 ld de, EnemyMonMoves ld b, EnemyMonMovesEnd - EnemyMonMoves + 1 @@ -140,7 +149,10 @@ AI_Setup: ; 385e0 AI_Types: ; 38635 -; Use super-effective moves. +; Dismiss any move that the player is immune to. +; Encourage super-effective moves. +; Discourage not very effective moves unless +; all damaging moves are of the same type. ld hl, Buffer1 - 1 ld de, EnemyMonMoves @@ -229,7 +241,7 @@ AI_Types: ; 38635 AI_Offensive: ; 386a2 -; Discourage non-damaging moves. +; Greatly discourage non-damaging moves. ld hl, Buffer1 - 1 ld de, EnemyMonMoves @@ -391,6 +403,9 @@ AI_Smart: ; 386be AI_Smart_Sleep: ; 387e3 +; Greatly encourage sleep inducing moves if the enemy has either Dream Eater or Nightmare. +; 50% chance to greatly encourage sleep inducing moves otherwise. + ld b, EFFECT_DREAM_EATER call AIHasMoveEffect jr c, .asm_387f0 @@ -415,14 +430,19 @@ AI_Smart_LeechHit: ; 387f7 callab Function347c8 pop hl +; 60% chance to discourage this move if not very effective. ld a, [$d265] cp 10 ; 1.0 jr c, .asm_38815 + +; Do nothing if effectiveness is neutral. ret z +; Do nothing if enemy's HP is full. call AICheckEnemyMaxHP ret c +; 80% chance to encourage this move otherwise. call AI_80_20 ret c @@ -546,23 +566,31 @@ AI_Smart_LockOn: ; 3881d AI_Smart_Explosion: ; 388a6 +; Selfdestruct, Explosion + +; Unless this is the enemy's last Pokemon... push hl callba CountEnemyAliveMons pop hl jr nc, .asm_388b7 +; ...greatly discourage this move unless this is the player's last Pokemon too. push hl call AICheckLastPlayerMon pop hl jr nz, .asm_388c6 .asm_388b7 +; Greatly discourage this move if enemy's HP is above 50%. call AICheckEnemyHalfHP jr c, .asm_388c6 +; Do nothing if enemy's HP is below 25%. call AICheckEnemyQuarterHP ret nc +; If enemy's HP is between 25% and 50%, +; over 90% chance to greatly discourage this move. call Random cp 20 ret c @@ -576,9 +604,11 @@ AI_Smart_Explosion: ; 388a6 AI_Smart_DreamEater: ; 388ca +; 90% chance to greatly encourage this move. +; The AI_Basic layer will make sure that +; Dream Eater is only used against sleeping targets. call Random - - cp $19 + cp 25 ret c dec [hl] dec [hl] @@ -588,17 +618,22 @@ AI_Smart_DreamEater: ; 388ca AI_Smart_EvasionUp: ; 388d4 + +; Dismiss this move if enemy's evasion can't raise anymore. ld a, [EnemyEvaLevel] cp $d jp nc, AIDiscourageMove +; If enemy's HP is full... call AICheckEnemyMaxHP jr nc, .asm_388f2 +; ...greatly encourage this move if player is badly poisoned. ld a, [PlayerSubStatus5] bit SUBSTATUS_TOXIC, a jr nz, .asm_388ef +; ...70% chance to greatly encourage this move if player is not badly poisoned. call Random cp $b2 jr nc, .asm_38911 @@ -609,21 +644,27 @@ AI_Smart_EvasionUp: ; 388d4 ret .asm_388f2 + +; Greatly discourage this move if enemy's HP is below 25%. call AICheckEnemyQuarterHP jr nc, .asm_3890f +; If enemy's HP is above 25% but not full, 4% chance to greatly encourage this move. call Random cp $a jr c, .asm_388ef +; If enemy's HP is between 25% and 50%,... call AICheckEnemyHalfHP jr nc, .asm_3890a +; If enemy's HP is above 50% but not full, 20% chance to greatly encourage this move. call AI_80_20 jr c, .asm_388ef jr .asm_38911 .asm_3890a +; ...50% chance to greatly discourage this move. call AI_50_50 jr c, .asm_38911 @@ -631,6 +672,11 @@ AI_Smart_EvasionUp: ; 388d4 inc [hl] inc [hl] +; 30% chance to end up here if enemy's HP is full and player is not badly poisoned. +; 77% chance to end up here if enemy's HP is above 50% but not full. +; 96% chance to end up here if enemy's HP is between 25% and 50%. +; 100% chance to end up here if enemy's HP is below 25%. +; In other words, we only end up here if the move has not been encouraged or dismissed. .asm_38911 ld a, [PlayerSubStatus5] bit SUBSTATUS_TOXIC, a @@ -640,12 +686,14 @@ AI_Smart_EvasionUp: ; 388d4 bit SUBSTATUS_LEECH_SEED, a jr nz, .asm_38941 +; Discourage this move if enemy's evasion level is higher than player's accuracy level. ld a, [EnemyEvaLevel] ld b, a ld a, [PlayerAccLevel] cp b jr c, .asm_38936 +; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout. ld a, [PlayerFuryCutterCount] and a jr nz, .asm_388ef @@ -659,6 +707,9 @@ AI_Smart_EvasionUp: ; 388d4 inc [hl] ret +; Player is badly poisoned. +; 80% chance to greatly encourage this move. +; This would counter any previous discouragement. .asm_38938 call Random cp $50 @@ -667,6 +718,9 @@ AI_Smart_EvasionUp: ; 388d4 dec [hl] ret +; Player is seeded. +; 50% chance to encourage this move. +; This would partly counter any previous discouragement. .asm_38941 call AI_50_50 ret c @@ -677,10 +731,14 @@ AI_Smart_EvasionUp: ; 388d4 AI_Smart_AlwaysHit: ; 38947 +; 80% chance to greatly encourage this move if either... + +; ...enemy's accuracy level has been lowered three or more stages ld a, [EnemyAccLevel] cp $5 jr c, .asm_38954 +; ...or player's evasion level has been raised three or more stages. ld a, [PlayerEvaLevel] cp $a ret c @@ -696,27 +754,37 @@ AI_Smart_AlwaysHit: ; 38947 AI_Smart_MirrorMove: ; 3895b + +; If the player did not use any move last turn... ld a, [LastEnemyCounterMove] and a jr nz, .asm_38968 - call AICompareSpeed +; ...do nothing if enemy is slower than player + call AICompareSpeed ret nc +; ...or dismiss this move if enemy is faster than player. jp AIDiscourageMove +; If the player did use a move last turn... .asm_38968 push hl - ld hl, GoodMoves + ld hl, UsefulMoves ld de, 1 call IsInArray pop hl + +; ...do nothing if he didn't use a useful move. ret nc +; If he did, 50% chance to encourage this move... call AI_50_50 ret c dec [hl] + +; ...and 90% chance to encourage this move again if the enemy is faster. call AICompareSpeed ret nc @@ -730,16 +798,21 @@ AI_Smart_MirrorMove: ; 3895b AI_Smart_AccuracyDown: ; 38985 + +; If player's HP is full... call AICheckPlayerMaxHP jr nc, .asm_389a0 +; ...and enemy's HP is above 50%... call AICheckEnemyHalfHP jr nc, .asm_389a0 +; ...greatly encourage this move if player is badly poisoned. ld a, [PlayerSubStatus5] bit SUBSTATUS_TOXIC, a jr nz, .asm_3899d +; ...70% chance to greatly encourage this move if player is not badly poisoned. call Random cp $b2 jr nc, .asm_389bf @@ -750,20 +823,26 @@ AI_Smart_AccuracyDown: ; 38985 ret .asm_389a0 + +; Greatly discourage this move if player's HP is below 25%. call AICheckPlayerQuarterHP jr nc, .asm_389bd +; If player's HP is above 25% but not full, 4% chance to greatly encourage this move. call Random cp $a jr c, .asm_3899d +; If player's HP is between 25% and 50%,... call AICheckPlayerHalfHP jr nc, .asm_389b8 +; If player's HP is above 50% but not full, 20% chance to greatly encourage this move. call AI_80_20 jr c, .asm_3899d jr .asm_389bf +; ...50% chance to greatly discourage this move. .asm_389b8 call AI_50_50 jr c, .asm_389bf @@ -772,6 +851,7 @@ AI_Smart_AccuracyDown: ; 38985 inc [hl] inc [hl] +; We only end up here if the move has not been already encouraged. .asm_389bf ld a, [PlayerSubStatus5] bit SUBSTATUS_TOXIC, a @@ -781,12 +861,14 @@ AI_Smart_AccuracyDown: ; 38985 bit SUBSTATUS_LEECH_SEED, a jr nz, .asm_389ef +; Discourage this move if enemy's evasion level is higher than player's accuracy level. ld a, [EnemyEvaLevel] ld b, a ld a, [PlayerAccLevel] cp b jr c, .asm_389e4 +; Greatly encourage this move if the player is in the middle of Fury Cutter or Rollout. ld a, [PlayerFuryCutterCount] and a jr nz, .asm_3899d @@ -799,6 +881,9 @@ AI_Smart_AccuracyDown: ; 38985 inc [hl] ret +; Player is badly poisoned. +; 80% chance to greatly encourage this move. +; This would counter any previous discouragement. .asm_389e6 call Random cp $50 @@ -807,6 +892,9 @@ AI_Smart_AccuracyDown: ; 38985 dec [hl] ret +; Player is seeded. +; 50% chance to encourage this move. +; This would partly counter any previous discouragement. .asm_389ef call AI_50_50 ret c @@ -817,6 +905,8 @@ AI_Smart_AccuracyDown: ; 38985 AI_Smart_Haze: ; 389f5 + +; 85% chance to encourage this move if any of enemy's stat levels is lower than -2. push hl ld hl, EnemyAtkLevel ld c, $8 @@ -828,6 +918,7 @@ AI_Smart_Haze: ; 389f5 jr c, .asm_38a12 jr .asm_389fb +; 85% chance to encourage this move if any of player's stat levels is higher than +2. .asm_38a05 ld hl, PlayerAtkLevel ld c, $8 @@ -846,6 +937,9 @@ AI_Smart_Haze: ; 389f5 dec [hl] ret +; Discourage this move if neither: +; Any of enemy's stat levels is lower than -2. +; Any of player's stat levels is higher than +2. .asm_38a1b pop hl inc [hl] @@ -854,6 +948,8 @@ AI_Smart_Haze: ; 389f5 AI_Smart_Bide: ; 38a1e +; 90% chance to discourage this move unless enemy's HP is full. + call AICheckEnemyMaxHP ret c call Random @@ -865,10 +961,16 @@ AI_Smart_Bide: ; 38a1e AI_Smart_Whirlwind: ; 38a2a +; Whirlwind, Roar. + +; Discourage this move if the player has not shown +; a super-effective move against the enemy. +; Consider player's type(s) if its moves are unknown. + push hl callab Function3484e ld a, [$c716] - cp $a + cp 10 ; neutral pop hl ret c inc [hl] @@ -880,6 +982,10 @@ AI_Smart_Heal: AI_Smart_MorningSun: AI_Smart_Synthesis: AI_Smart_Moonlight: ; 38a3a +; 90% chance to greatly encourage this move if enemy's HP is below 25%. +; Discourage this move if enemy's HP is higher than 50%. +; Do nothing otherwise. + call AICheckEnemyQuarterHP jr nc, .asm_38a45 call AICheckEnemyHalfHP @@ -899,6 +1005,8 @@ AI_Smart_Moonlight: ; 38a3a AI_Smart_Toxic: AI_Smart_LeechSeed: ; 38a4e +; Discourage this move if player's HP is below 50%. + call AICheckPlayerHalfHP ret c inc [hl] @@ -908,6 +1016,8 @@ AI_Smart_LeechSeed: ; 38a4e AI_Smart_LightScreen: AI_Smart_Reflect: ; 38a54 +; Over 90% chance to discourage this move unless enemy's HP is full. + call AICheckEnemyMaxHP ret c call Random @@ -919,6 +1029,9 @@ AI_Smart_Reflect: ; 38a54 AI_Smart_Ohko: ; 38a60 +; Dismiss this move if player's level is higher than enemy's level. +; Else, discourage this move is player's HP is below 50%. + ld a, [BattleMonLevel] ld b, a ld a, [EnemyMonLevel] @@ -932,10 +1045,15 @@ AI_Smart_Ohko: ; 38a60 AI_Smart_Bind: ; 38a71 +; Bind, Wrap, Fire Spin, Clamp + +; 50% chance to discourage this move if the player is already trapped. ld a, [$c730] and a jr nz, .asm_38a8b +; 50% chance to greatly encourage this move if player is either +; badly poisoned, in love, identified, stuck in Rollout, or has a Nightmare. ld a, [PlayerSubStatus5] bit SUBSTATUS_TOXIC, a jr nz, .asm_38a91 @@ -944,10 +1062,12 @@ AI_Smart_Bind: ; 38a71 and 1<<SUBSTATUS_IN_LOVE | 1<<SUBSTATUS_ROLLOUT | 1<<SUBSTATUS_IDENTIFIED | 1<<SUBSTATUS_NIGHTMARE jr nz, .asm_38a91 +; Else, 50% chance to greatly encourage this move if it's the player's Pokemon first turn. ld a, [PlayerTurnsTaken] and a jr z, .asm_38a91 +; 50% chance to discourage this move otherwise. .asm_38a8b call AI_50_50 ret c @@ -1021,13 +1141,17 @@ AI_Smart_Unused2B: ; 38a9c AI_Smart_Confuse: ; 38adb + +; 90% chance to discourage this move if player's HP is between 25% and 50%. call AICheckPlayerHalfHP ret c call Random cp $19 jr c, .asm_38ae7 inc [hl] + .asm_38ae7 +; Discourage again if player's HP is below 25%. call AICheckPlayerQuarterHP ret c inc [hl] @@ -1036,12 +1160,18 @@ AI_Smart_Confuse: ; 38adb AI_Smart_SpDefenseUp2: ; 38aed + +; Discourage this move if enemy's HP is lower than 50%. call AICheckEnemyHalfHP jr nc, .asm_38b10 +; Discourage this move if enemy's special defense level is higher than +3. ld a, [EnemySDefLevel] cp $b jr nc, .asm_38b10 + +; 80% chance to greatly encourage this move if +; enemy's Special Defense level is lower than +2, and the player is of a special type. cp $9 ret nc @@ -1066,11 +1196,18 @@ AI_Smart_SpDefenseUp2: ; 38aed AI_Smart_Fly: ; 38b12 +; Fly, Dig + +; Greatly encourage this move if the player is +; flying or underground, and slower than the enemy. + ld a, [PlayerSubStatus3] and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND ret z + call AICompareSpeed ret nc + dec [hl] dec [hl] dec [hl] @@ -1079,6 +1216,8 @@ AI_Smart_Fly: ; 38b12 AI_Smart_SuperFang: ; 38b20 +; Discourage this move if player's HP is below 25%. + call AICheckPlayerQuarterHP ret c inc [hl] @@ -1087,8 +1226,13 @@ AI_Smart_SuperFang: ; 38b20 AI_Smart_Paralyze: ; 38b26 + +; 50% chance to discourage this move if player's HP is below 25%. call AICheckPlayerQuarterHP jr nc, .asm_38b3a + +; 80% chance to greatly encourage this move +; if enemy is slower than player and its HP is above 25%. call AICompareSpeed ret c call AICheckEnemyQuarterHP @@ -1108,6 +1252,13 @@ AI_Smart_Paralyze: ; 38b26 AI_Smart_SpeedDownHit: ; 38b40 +; Icy Wind + +; Almost 90% chance to greatly encourage this move if the following conditions all meet: +; Enemy's HP is higher than 25%. +; It's the first turn of player's Pokemon. +; Player is faster than enemy. + ld a, [wEnemyMoveStruct + MOVE_ANIM] cp ICY_WIND ret nz @@ -1128,6 +1279,8 @@ AI_Smart_SpeedDownHit: ; 38b40 AI_Smart_Substitute: ; 38b5c +; Dismiss this move if enemy's HP is below 50%. + call AICheckEnemyHalfHP ret c jp AIDiscourageMove @@ -1137,6 +1290,8 @@ AI_Smart_Substitute: ; 38b5c AI_Smart_HyperBeam: ; 38b63 call AICheckEnemyHalfHP jr c, .asm_38b72 + +; 50% chance to encourage this move if enemy's HP is below 25%. call AICheckEnemyQuarterHP ret c call AI_50_50 @@ -1145,6 +1300,7 @@ AI_Smart_HyperBeam: ; 38b63 ret .asm_38b72 +; If enemy's HP is above 50%, discourage this move at random call Random cp 40 ret c @@ -1161,11 +1317,13 @@ AI_Smart_Rage: ; 38b7f bit SUBSTATUS_RAGE, a jr z, .asm_38b9b +; If enemy's Rage is building, 50% chance to encourage this move. call AI_50_50 jr c, .asm_38b8c dec [hl] +; Encourage this move based on Rage's counter. .asm_38b8c ld a, [$c72c] cp $2 @@ -1178,9 +1336,11 @@ AI_Smart_Rage: ; 38b7f ret .asm_38b9b +; If enemy's Rage is not building, discourage this move if enemy's HP is below 50%. call AICheckEnemyHalfHP jr nc, .asm_38ba6 +; 50% chance to encourage this move otherwise. call AI_80_20 ret nc dec [hl] @@ -1222,7 +1382,7 @@ AI_Smart_Mimic: ; 38ba8 .asm_38bd4 ld a, [LastEnemyCounterMove] push hl - ld hl, GoodMoves + ld hl, UsefulMoves ld de, 1 call IsInArray @@ -1340,7 +1500,7 @@ AI_Smart_Encore: ; 38c3b .asm_38c68 push hl ld a, [LastEnemyCounterMove] - ld hl, .table_38c85 + ld hl, .EncoreMoves ld de, 1 call IsInArray pop hl @@ -1360,7 +1520,7 @@ AI_Smart_Encore: ; 38c3b inc [hl] ret -.table_38c85 +.EncoreMoves: db SWORDS_DANCE db WHIRLWIND db LEER @@ -1396,6 +1556,8 @@ AI_Smart_Encore: ; 38c3b AI_Smart_PainSplit: ; 38ca4 +; Discourage this move if [enemy's current HP * 2 > player's current HP]. + push hl ld hl, EnemyMonHP ld b, [hl] @@ -1417,6 +1579,9 @@ AI_Smart_PainSplit: ; 38ca4 AI_Smart_Snore: AI_Smart_SleepTalk: ; 38cba +; Greatly encourage this move if enemy is fast asleep. +; Greatly discourage this move otherwise. + ld a, [EnemyMonStatus] and $7 cp $1 @@ -1436,6 +1601,9 @@ AI_Smart_SleepTalk: ; 38cba AI_Smart_DefrostOpponent: ; 38ccb +; Greatly encourage this move if enemy is frozen. +; No move has EFFECT_DEFROST_OPPONENT, so this layer is unused. + ld a, [EnemyMonStatus] and $20 ret z @@ -1512,6 +1680,8 @@ Function_0x38d16; 38d16 AI_Smart_DestinyBond: AI_Smart_Reversal: AI_Smart_SkullBash: ; 38d19 +; Discourage this move if enemy's HP is above 25%. + call AICheckEnemyQuarterHP ret nc inc [hl] @@ -1520,6 +1690,10 @@ AI_Smart_SkullBash: ; 38d19 AI_Smart_HealBell: ; 38d1f +; Dismiss this move if none of the opponent's Pokemon is statused. +; Encourage this move if the enemy is statused. +; 50% chance to greatly encourage this move if the enemy is fast asleep or frozen. + push hl ld a, [OTPartyCount] ld b, a @@ -1533,6 +1707,7 @@ AI_Smart_HealBell: ; 38d1f or [hl] jr z, .next + ; status dec hl dec hl dec hl @@ -1575,12 +1750,14 @@ AI_Smart_HealBell: ; 38d1f AI_Smart_PriorityHit: ; 38d5a call AICompareSpeed - ret c + +; Dismiss this move if the player is flying or underground. ld a, [PlayerSubStatus3] and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND jp nz, AIDiscourageMove +; Greatly encourage this move if it will KO the player. ld a, $1 ld [hBattleTurn], a push hl @@ -1605,6 +1782,8 @@ AI_Smart_PriorityHit: ; 38d5a AI_Smart_Thief: ; 38d93 +; Don't use Thief unless it's the only move available. + ld a, [hl] add $1e ld [hl], a @@ -1659,7 +1838,7 @@ AI_Smart_Disable: ; 38dd1 push hl ld a, [LastEnemyCounterMove] - ld hl, GoodMoves + ld hl, UsefulMoves ld de, 1 call IsInArray @@ -1695,18 +1874,22 @@ AI_Smart_MeanLook: ; 38dfb pop hl jp z, AIDiscourageMove +; 80% chance to greatly encourage this move if the enemy is badly poisoned (weird). ld a, [EnemySubStatus5] bit SUBSTATUS_TOXIC, a jr nz, .asm_38e26 +; 80% chance to greatly encourage this move if the player is either +; in love, identified, stuck in Rollout, or has a Nightmare. ld a, [PlayerSubStatus1] and 1<<SUBSTATUS_IN_LOVE | 1<<SUBSTATUS_ROLLOUT | 1<<SUBSTATUS_IDENTIFIED | 1<<SUBSTATUS_NIGHTMARE jr nz, .asm_38e26 +; Otherwise, discourage this move unless the player only has not very effective moves against the enemy. push hl callab Function3484e ld a, [$c716] - cp $b + cp $b ; not very effective pop hl ret nc @@ -1752,6 +1935,10 @@ AICheckLastPlayerMon: ; 38e2e AI_Smart_Nightmare: ; 38e4a +; 50% chance to encourage this move. +; The AI_Basic layer will make sure that +; Dream Eater is only used against sleeping targets. + call AI_50_50 ret c dec [hl] @@ -1760,6 +1947,8 @@ AI_Smart_Nightmare: ; 38e4a AI_Smart_FlameWheel: ; 38e50 +; Use this move if the enemy is frozen. + ld a, [EnemyMonStatus] bit FRZ, a ret z @@ -1953,7 +2142,7 @@ AI_Smart_PerishSong: ; 38f4a ld a, [PlayerSubStatus5] bit SUBSTATUS_CANT_RUN, a - jr nz, .asm_38f6f + jr nz, .yes push hl callab Function3484e @@ -1968,7 +2157,7 @@ AI_Smart_PerishSong: ; 38f4a inc [hl] ret -.asm_38f6f +.yes call AI_50_50 ret c @@ -1984,6 +2173,8 @@ AI_Smart_PerishSong: ; 38f4a AI_Smart_Sandstorm: ; 38f7a + +; Greatly discourage this move if the player is immune to Sandstorm damage. ld a, [BattleMonType1] push hl ld hl, .SandstormImmuneTypes @@ -2000,9 +2191,11 @@ AI_Smart_Sandstorm: ; 38f7a pop hl jr c, .asm_38fa5 +; Discourage this move if player's HP is below 50%. call AICheckPlayerHalfHP jr nc, .asm_38fa6 +; 50% chance to encourage this move otherwise. call AI_50_50 ret c @@ -2069,6 +2262,8 @@ AI_Smart_Endure: ; 38fac AI_Smart_FuryCutter: ; 38fdb +; Encourage this move based on Fury Cutter's count. + ld a, [EnemyFuryCutterCount] and a jr z, .end @@ -2092,6 +2287,9 @@ AI_Smart_FuryCutter: ; 38fdb AI_Smart_Rollout: ; 38fef +; Rollout, Fury Cutter + +; 80% chance to discourage this move if the enemy is in love, confused, or paralyzed. ld a, [EnemySubStatus1] bit SUBSTATUS_IN_LOVE, a jr nz, .asm_39020 @@ -2104,6 +2302,8 @@ AI_Smart_Rollout: ; 38fef bit PAR, a jr nz, .asm_39020 +; 80% chance to discourage this move if the enemy's HP is below 25%, +; or if accuracy or evasion modifiers favour the player. call AICheckEnemyQuarterHP jr nc, .asm_39020 @@ -2114,6 +2314,7 @@ AI_Smart_Rollout: ; 38fef cp 8 jr nc, .asm_39020 +; Otherwise, 80% chance to greatly encourage this move. call Random cp 200 ret nc @@ -2131,6 +2332,9 @@ AI_Smart_Rollout: ; 38fef AI_Smart_Swagger: AI_Smart_Attract: ; 39026 +; 80% chance to encourage this move during the first turn of player's Pokemon. +; 80% chance to discourage this move otherwise. + ld a, [PlayerTurnsTaken] and a jr z, .first_turn @@ -2150,6 +2354,8 @@ AI_Smart_Attract: ; 39026 AI_Smart_Safeguard: ; 3903a +; 80% chance to discourage this move if player's HP is below 50%. + call AICheckPlayerHalfHP ret c call AI_80_20 @@ -2161,6 +2367,8 @@ AI_Smart_Safeguard: ; 3903a AI_Smart_Magnitude: AI_Smart_Earthquake: ; 39044 + +; Greatly encourage this move if the player is underground and the enemy is faster. ld a, [LastEnemyCounterMove] cp DIG ret nz @@ -2176,22 +2384,28 @@ AI_Smart_Earthquake: ; 39044 ret .could_dig - ; Try to predict if the player - ; will use Dig this turn. + ; Try to predict if the player will use Dig this turn. + + ; 50% chance to encourage this move if the enemy is slower than the player. call AICompareSpeed ret c + call AI_50_50 ret c + dec [hl] ret ; 39062 AI_Smart_BatonPass: ; 39062 +; Discourage this move if the player hasn't shown super-effective moves against the enemy. +; Consider player's type(s) if its moves are unknown. + push hl callab Function3484e ld a, [$c716] - cp 10 ; 1.0 + cp 10 ; neutral pop hl ret c inc [hl] @@ -2200,6 +2414,9 @@ AI_Smart_BatonPass: ; 39062 AI_Smart_Pursuit: ; 39072 +; 50% chance to greatly encourage this move if player's HP is below 25%. +; 80% chance to discourage this move otherwise. + call AICheckPlayerQuarterHP jr nc, .asm_3907d call AI_80_20 @@ -2217,6 +2434,9 @@ AI_Smart_Pursuit: ; 39072 AI_Smart_RapidSpin: ; 39084 +; 80% chance to greatly encourage this move if the enemy is +; trapped (Bind effect), seeded, or scattered with spikes. + ld a, [$c731] and a jr nz, .asm_39097 @@ -2243,22 +2463,28 @@ AI_Smart_HiddenPower: ; 3909e push hl ld a, 1 ld [hBattleTurn], a + +; Calculate Hidden Power's type and base power based on enemy's DVs. callab HiddenPowerDamage callab Function347c8 pop hl +; Discourage Hidden Power if not very effective. ld a, [$d265] cp 10 jr c, .bad +; Discourage Hidden Power if its base power is lower than 50. ld a, d cp 50 jr c, .bad +; Encourage Hidden Power if super-effective. ld a, [$d265] cp 11 jr nc, .good +; Encourage Hidden Power if its base power is 70. ld a, d cp 70 ret c @@ -2274,6 +2500,9 @@ AI_Smart_HiddenPower: ; 3909e AI_Smart_RainDance: ; 390cb + +; Greatly discourage this move if it would favour the player type-wise. +; Particularly, if the player is a Water-type. ld a, [BattleMonType1] cp WATER jr z, AIBadWeatherType @@ -2308,6 +2537,9 @@ RainDanceMoves: ; 390e7 AI_Smart_SunnyDay: ; 390f3 + +; Greatly discourage this move if it would favour the player type-wise. +; Particularly, if the player is a Fire-type. ld a, [BattleMonType1] cp FIRE jr z, AIBadWeatherType @@ -2328,13 +2560,19 @@ AI_Smart_SunnyDay: ; 390f3 AI_Smart_WeatherMove: ; 3910d +; Rain Dance, Sunny Day + +; Greatly discourage this move if the enemy doesn't have +; one of the useful Rain Dance or Sunny Day moves. call AIHasMoveInArray pop hl jr nc, AIBadWeatherType +; Greatly discourage this move if player's HP is below 50%. call AICheckPlayerHalfHP jr nc, AIBadWeatherType +; 50% chance to encourage this move otherwise. call AI_50_50 ret c @@ -2350,13 +2588,19 @@ AIBadWeatherType: ; 3911e ; 39122 AIGoodWeatherType: ; 39122 +; Rain Dance, Sunny Day + +; Greatly encourage this move if it would disfavour the player type-wise and player's HP is above 50%... call AICheckPlayerHalfHP ret nc +; ...as long as one of the following conditions meet: +; It's the first turn of the player's Pokemon. ld a, [PlayerTurnsTaken] and a jr z, .good +; Or it's the first turn of the enemy's Pokemon. ld a, [EnemyTurnsTaken] and a ret nz @@ -2382,16 +2626,19 @@ SunnyDayMoves: ; 39134 AI_Smart_BellyDrum: ; 3913d +; Dismiss this move if enemy's attack is higher than +2 or if enemy's HP is below 50%. +; Else, discourage this move if enemy's HP is not full. + ld a, [EnemyAtkLevel] cp $a jr nc, .asm_3914d call AICheckEnemyMaxHP - ret c + inc [hl] - call AICheckEnemyHalfHP + call AICheckEnemyHalfHP ret c .asm_3914d @@ -2406,8 +2653,10 @@ AI_Smart_PsychUp: ; 39152 push hl ld hl, EnemyAtkLevel ld b, $8 - ld c, $64 + ld c, 100 +; Calculate the sum of all enemy's stat level modifiers. Add 100 first to prevent underflow. +; Put the result in c. c will range between 58 and 142. .asm_3915a ld a, [hli] sub $7 @@ -2416,9 +2665,11 @@ AI_Smart_PsychUp: ; 39152 dec b jr nz, .asm_3915a +; Calculate the sum of all player's stat level modifiers. Add 100 first to prevent underflow. +; Put the result in d. d will range between 58 and 142. ld hl, PlayerAtkLevel ld b, $8 - ld d, $64 + ld d, 100 .asm_39169 ld a, [hli] @@ -2428,19 +2679,25 @@ AI_Smart_PsychUp: ; 39152 dec b jr nz, .asm_39169 +; Greatly discourage this move if enemy's stat levels are higher than player's (if c>=d). ld a, c sub d pop hl jr nc, .asm_39188 +; Else, 80% chance to encourage this move unless player's accuracy level is lower than -1... ld a, [PlayerAccLevel] cp $6 ret c + +; ...or enemy's evasion level is higher than +0. ld a, [EnemyEvaLevel] cp $8 ret nc + call AI_80_20 ret c + dec [hl] ret @@ -2518,13 +2775,15 @@ AI_Smart_MirrorCoat: ; 3918b AI_Smart_Twister: AI_Smart_Gust: ; 391d5 + +; Greatly encourage this move if the player is flying and the enemy is faster. ld a, [LastEnemyCounterMove] cp FLY ret nz ld a, [PlayerSubStatus3] bit SUBSTATUS_FLYING, a - jr z, .asm_391e9 + jr z, .couldFly call AICompareSpeed ret nc @@ -2533,7 +2792,10 @@ AI_Smart_Gust: ; 391d5 dec [hl] ret -.asm_391e9 +; Try to predict if the player will use Fly this turn. +.couldFly + +; 50% chance to encourage this move if the enemy is slower than the player. call AICompareSpeed ret c call AI_50_50 @@ -2544,6 +2806,9 @@ AI_Smart_Gust: ; 391d5 AI_Smart_FutureSight: ; 391f3 +; Greatly encourage this move if the player is +; flying or underground, and slower than the enemy. + call AICompareSpeed ret nc @@ -2558,6 +2823,8 @@ AI_Smart_FutureSight: ; 391f3 AI_Smart_Stomp: ; 39200 +; 80% chance to encourage this move if the player has used Minimize. + ld a, [$c6fe] and a ret z @@ -2571,6 +2838,9 @@ AI_Smart_Stomp: ; 39200 AI_Smart_Solarbeam: ; 3920b +; 80% chance to encourage this move when it's sunny. +; 90% chance to discourage this move when it's raining. + ld a, [Weather] cp WEATHER_SUN jr z, .asm_3921e @@ -2597,6 +2867,8 @@ AI_Smart_Solarbeam: ; 3920b AI_Smart_Thunder: ; 39225 +; 90% chance to discourage this move when it's sunny. + ld a, [Weather] cp WEATHER_SUN ret nz @@ -2611,6 +2883,8 @@ AI_Smart_Thunder: ; 39225 AICompareSpeed: ; 39233 +; Return carry if enemy is faster than player. + push bc ld a, [EnemyMonSpeed + 1] ld b, a @@ -2647,6 +2921,7 @@ AICheckEnemyMaxHP: ; 39251 AICheckMaxHP: ; 3925a ; Return carry if hp at de matches max hp at hl. + ld a, [de] inc de cp [hl] @@ -2762,6 +3037,7 @@ AICheckPlayerQuarterHP: ; 392b3 AIHasMoveEffect: ; 392ca ; Return carry if the enemy has move b. + push hl ld hl, EnemyMonMoves ld c, EnemyMonMovesEnd - EnemyMonMoves @@ -2827,7 +3103,7 @@ AIHasMoveInArray: ; 392e6 ; 39301 -GoodMoves: ; 39301 +UsefulMoves: ; 39301 ; Moves that are usable all-around. db DOUBLE_EDGE db SING @@ -2853,14 +3129,17 @@ GoodMoves: ; 39301 AI_Opportunist: ; 39315 -; Don't use stall moves when the player's HP is low. +; Discourage stall moves when the enemy's HP is low. +; Do nothing if enemy's HP is above 50%. call AICheckEnemyHalfHP ret c +; Discourage stall moves if enemy's HP is below 25%. call AICheckEnemyQuarterHP jr nc, .asm_39322 - + +; 50% chance to discourage stall moves if enemy's HP is between 25% and 50%. call AI_50_50 ret c @@ -2937,6 +3216,10 @@ AI_Opportunist: ; 39315 AI_Aggressive: ; 39369 ; Use whatever does the most damage. +; Discourage all damaging moves but the one that does the most damage. +; If no damaging move deals damage to the player (immune), +; no move will be discouraged + ; Figure out which attack does the most damage and put it in c. ld hl, EnemyMonMoves ld bc, 0 @@ -2963,6 +3246,7 @@ AI_Aggressive: ; 39369 pop de pop hl +; Update current move if damage is highest so far ld a, [CurDamage + 1] cp e ld a, [CurDamage] @@ -2998,6 +3282,7 @@ AI_Aggressive: ; 39369 cp EnemyMonMovesEnd - EnemyMonMoves + 1 jr z, .done +; Ignore this move if it is the highest damaging one. cp c ld a, [de] inc de @@ -3006,15 +3291,19 @@ AI_Aggressive: ; 39369 call AIGetEnemyMove +; Ignore this move if its power is 0 or 1. +; Moves such as Seismic Toss, Hidden Power, +; Counter and Fissure have a base power of 1. ld a, [wEnemyMoveStruct + MOVE_POWER] cp 2 jr c, .checkmove2 +; Ignore this move if it is reckless. push hl push de push bc ld a, [wEnemyMoveStruct + MOVE_EFFECT] - ld hl, .aggressivemoves + ld hl, .RecklessMoves ld de, 1 call IsInArray pop bc @@ -3022,13 +3311,14 @@ AI_Aggressive: ; 39369 pop hl jr c, .checkmove2 +; If we made it this far, discourage this move. inc [hl] jr .checkmove2 .done ret -.aggressivemoves +.RecklessMoves: db EFFECT_EXPLOSION db EFFECT_RAMPAGE db EFFECT_MULTI_HIT @@ -3064,7 +3354,7 @@ AIDamageCalc: ; 393e7 AI_Cautious: ; 39418 -; Don't use moves with residual effects after turn 1. +; 90% chance to discourage moves with residual effects after the first turn. ld a, [EnemyTurnsTaken] and a @@ -3121,7 +3411,7 @@ AI_Cautious: ; 39418 AI_Status: ; 39453 -; Don't use status moves that don't affect the player. +; Dismiss status moves that don't affect the player. ld hl, Buffer1 - 1 ld de, EnemyMonMoves @@ -3185,7 +3475,8 @@ AI_Status: ; 39453 AI_Risky: ; 394a9 -; Use any move that will KO the opponent. +; Use any move that will KO the target. +; Risky moves will often be an exception (see below). ld hl, Buffer1 - 1 ld de, EnemyMonMoves @@ -3212,13 +3503,14 @@ AI_Risky: ; 394a9 ; Don't use risky moves at max hp. ld a, [wEnemyMoveStruct + MOVE_EFFECT] ld de, 1 - ld hl, .riskymoves + ld hl, .RiskyMoves call IsInArray jr nc, .checkko call AICheckEnemyMaxHP jr c, .nextmove +; Else, 80% chance to exclude them. call Random cp 200 ; 1/5 jr c, .nextmove @@ -3250,7 +3542,7 @@ AI_Risky: ; 394a9 pop de jr .checkmove -.riskymoves +.RiskyMoves: db EFFECT_EXPLOSION db EFFECT_OHKO db $ff @@ -3272,6 +3564,8 @@ AIDiscourageMove: ; 39503 AIGetEnemyMove: ; 39508 +; Load attributes of move a into ram + push hl push de push bc @@ -41695,6 +41695,8 @@ TrainerClassNames:: ; 2c1ef AI_Redundant: ; 2c41a ; Check if move effect c will fail because it's already been used. +; Return z if the move is a good choice. +; Return nz if the move is a bad choice. ld a, c ld de, 3 ld hl, .Moves @@ -47162,7 +47164,7 @@ AIChooseMove: ; 440ce ld a, c cp 16 ; up to 16 scoring layers - jr z, .asm_4415e + jr z, .DecrementScores push bc ld d, BANK(TrainerClassAttributes) @@ -47191,28 +47193,36 @@ AIChooseMove: ; 440ce jr .CheckLayer -.asm_4415e +; Decrement the scores of all moves one by one until one reaches 0. +.DecrementScores ld hl, Buffer1 ld de, EnemyMonMoves ld c, EnemyMonMovesEnd - EnemyMonMoves -.asm_44166 + +.DecrementNextScore ; If the enemy has no moves, this will infinite. ld a, [de] inc de and a - jr z, .asm_4415e + jr z, .DecrementScores + ; We are done whenever a score reaches 0 dec [hl] - jr z, .asm_44174 + jr z, .PickLowestScoreMoves + ; If we just decremented the fourth move's score, go back to the first move inc hl dec c - jr z, .asm_4415e + jr z, .DecrementScores - jr .asm_44166 + jr .DecrementNextScore -.asm_44174 +; In order to avoid bias towards the moves located first in memory, increment the scores +; that were decremented one more time than the rest (in case there was a tie). +; This means that the minimum score will be 1. +.PickLowestScoreMoves ld a, c + .asm_44175 inc [hl] dec hl @@ -47223,11 +47233,15 @@ AIChooseMove: ; 440ce ld hl, Buffer1 ld de, EnemyMonMoves ld c, NUM_MOVES + +; Give a score of 0 to a blank move .asm_44184 ld a, [de] and a jr nz, .asm_44189 - ld [hl], a + ld [hl], a + +; Disregard the move if its score is not 1 .asm_44189 ld a, [hl] dec a @@ -47235,6 +47249,7 @@ AIChooseMove: ; 440ce xor a ld [hli], a jr .asm_44193 + .asm_44191 ld a, [de] ld [hli], a @@ -47243,7 +47258,8 @@ AIChooseMove: ; 440ce dec c jr nz, .asm_44184 -.asm_44197 +; Randomly choose one of the moves with a score of 1 +.ChooseMove ld hl, Buffer1 call Random and 3 @@ -47252,7 +47268,7 @@ AIChooseMove: ; 440ce add hl, bc ld a, [hl] and a - jr z, .asm_44197 + jr z, .ChooseMove ld [CurEnemyMove], a ld a, c |