ref: 81e2a3f0cfd4a280196b1776de6ae7df334ad85c
parent: 78d16c1efae40955d76c78215e1893c56e8e7e3e
parent: d430cccdfb7cd7146b6a67a3928ae34e793ca7e8
author: yenatch <yenatch@gmail.com>
date: Wed Oct 22 22:41:52 EDT 2014
Merge remote-tracking branch 'xcrystal/master' into master Conflicts: battle/ai/scoring.asm main.asm
--- 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:
--- a/Makefile
+++ b/Makefile
@@ -43,7 +43,7 @@
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
--- /dev/null
+++ b/Vagrantfile
@@ -1,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
--- a/battle/ai/scoring.asm
+++ b/battle/ai/scoring.asm
@@ -21,6 +21,9 @@
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 @@
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 @@
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_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_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_Offensive: ; 386a2
-; Discourage non-damaging moves.
+; Greatly discourage non-damaging moves.
ld hl, Buffer1 - 1
ld de, EnemyMonMoves
@@ -391,6 +403,9 @@
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 @@
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,11 +566,15 @@
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
@@ -557,12 +581,16 @@
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_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_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 @@
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 @@
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,6 +686,7 @@
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]
@@ -646,6 +693,7 @@
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 @@
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 @@
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_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_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_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 @@
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 @@
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,6 +861,7 @@
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]
@@ -787,6 +868,7 @@
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 @@
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 @@
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_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 @@
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 @@
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_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_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_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_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_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_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_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 @@
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,6 +1141,8 @@
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
@@ -1027,7 +1149,9 @@
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_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_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_SuperFang: ; 38b20
+; Discourage this move if player's HP is below 25%.
+
call AICheckPlayerQuarterHP
ret c
inc [hl]
@@ -1087,8 +1226,13 @@
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_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_Substitute: ; 38b5c
+; Dismiss this move if enemy's HP is below 50%.
+
call AICheckEnemyHalfHP
ret c
jp AIDiscourageMove
@@ -1137,6 +1290,8 @@
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 @@
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 @@
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 @@
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 @@
.asm_38bd4
ld a, [LastEnemyCounterMove]
push hl
- ld hl, GoodMoves
+ ld hl, UsefulMoves
ld de, 1
call IsInArray
@@ -1340,7 +1500,7 @@
.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 @@
inc [hl]
ret
-.table_38c85
+.EncoreMoves:
db SWORDS_DANCE
db WHIRLWIND
db LEER
@@ -1396,6 +1556,8 @@
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_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_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 @@
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_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 @@
or [hl]
jr z, .next
+ ; status
dec hl
dec hl
dec hl
@@ -1575,12 +1750,14 @@
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_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 @@
push hl
ld a, [LastEnemyCounterMove]
- ld hl, GoodMoves
+ ld hl, UsefulMoves
ld de, 1
call IsInArray
@@ -1695,18 +1874,22 @@
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 @@
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_FlameWheel: ; 38e50
+; Use this move if the enemy is frozen.
+
ld a, [EnemyMonStatus]
bit FRZ, a
ret z
@@ -1953,7 +2142,7 @@
ld a, [PlayerSubStatus5]
bit SUBSTATUS_CANT_RUN, a
- jr nz, .asm_38f6f
+ jr nz, .yes
push hl
callab Function3484e
@@ -1968,7 +2157,7 @@
inc [hl]
ret
-.asm_38f6f
+.yes
call AI_50_50
ret c
@@ -1984,6 +2173,8 @@
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 @@
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_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_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 @@
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 @@
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_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_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_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,12 +2384,15 @@
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
@@ -2188,10 +2399,13 @@
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_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_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 @@
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_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 @@
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_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 @@
; 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 @@
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 @@
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 @@
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 @@
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,6 +2775,8 @@
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
@@ -2524,7 +2783,7 @@
ld a, [PlayerSubStatus3]
bit SUBSTATUS_FLYING, a
- jr z, .asm_391e9
+ jr z, .couldFly
call AICompareSpeed
ret nc
@@ -2533,7 +2792,10 @@
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_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_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_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_Thunder: ; 39225
+; 90% chance to discourage this move when it's sunny.
+
ld a, [Weather]
cp WEATHER_SUN
ret nz
@@ -2611,6 +2883,8 @@
AICompareSpeed: ; 39233
+; Return carry if enemy is faster than player.
+
push bc
ld a, [EnemyMonSpeed + 1]
ld b, a
@@ -2647,6 +2921,7 @@
AICheckMaxHP: ; 3925a
; Return carry if hp at de matches max hp at hl.
+
ld a, [de]
inc de
cp [hl]
@@ -2762,6 +3037,7 @@
AIHasMoveEffect: ; 392ca
; Return carry if the enemy has move b.
+
push hl
ld hl, EnemyMonMoves
ld c, EnemyMonMovesEnd - EnemyMonMoves
@@ -2827,7 +3103,7 @@
; 39301
-GoodMoves: ; 39301
+UsefulMoves: ; 39301
; Moves that are usable all-around.
db DOUBLE_EDGE
db SING
@@ -2853,14 +3129,17 @@
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_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 @@
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 @@
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 @@
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,6 +3311,7 @@
pop hl
jr c, .checkmove2
+; If we made it this far, discourage this move.
inc [hl]
jr .checkmove2
@@ -3028,7 +3318,7 @@
.done
ret
-.aggressivemoves
+.RecklessMoves:
db EFFECT_EXPLOSION
db EFFECT_RAMPAGE
db EFFECT_MULTI_HIT
@@ -3064,7 +3354,7 @@
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_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_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,7 +3503,7 @@
; 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
@@ -3219,6 +3510,7 @@
call AICheckEnemyMaxHP
jr c, .nextmove
+; Else, 80% chance to exclude them.
call Random
cp 200 ; 1/5
jr c, .nextmove
@@ -3250,7 +3542,7 @@
pop de
jr .checkmove
-.riskymoves
+.RiskyMoves:
db EFFECT_EXPLOSION
db EFFECT_OHKO
db $ff
@@ -3272,6 +3564,8 @@
AIGetEnemyMove: ; 39508
+; Load attributes of move a into ram
+
push hl
push de
push bc
--- a/main.asm
+++ b/main.asm
@@ -41695,6 +41695,8 @@
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 @@
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 @@
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 @@
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 @@
xor a
ld [hli], a
jr .asm_44193
+
.asm_44191
ld a, [de]
ld [hli], a
@@ -47243,7 +47258,8 @@
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 @@
add hl, bc
ld a, [hl]
and a
- jr z, .asm_44197
+ jr z, .ChooseMove
ld [CurEnemyMove], a
ld a, c