Merge branch '_RHH/upcoming' into _RHH/pr/upcoming/merrpFollowers
This commit is contained in:
commit
ee1d14755a
@ -1352,6 +1352,22 @@
|
||||
.endm
|
||||
|
||||
@ callnative macros
|
||||
.macro savetarget
|
||||
callnative BS_SaveTarget
|
||||
.endm
|
||||
|
||||
.macro restoretarget
|
||||
callnative BS_RestoreTarget
|
||||
.endm
|
||||
|
||||
.macro saveattacker
|
||||
callnative BS_SaveAttacker
|
||||
.endm
|
||||
|
||||
.macro restoreattacker
|
||||
callnative BS_RestoreAttacker
|
||||
.endm
|
||||
|
||||
.macro metalburstdamagecalculator failInstr:req
|
||||
callnative BS_CalcMetalBurstDmg
|
||||
.4byte \failInstr
|
||||
@ -1774,14 +1790,6 @@
|
||||
various \battler, VARIOUS_SWITCHIN_ABILITIES
|
||||
.endm
|
||||
|
||||
.macro savetarget
|
||||
various BS_TARGET, VARIOUS_SAVE_TARGET
|
||||
.endm
|
||||
|
||||
.macro restoretarget
|
||||
various BS_TARGET, VARIOUS_RESTORE_TARGET
|
||||
.endm
|
||||
|
||||
.macro instanthpdrop battler:req
|
||||
various \battler, VARIOUS_INSTANT_HP_DROP
|
||||
.endm
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -5775,7 +5775,7 @@ BattleScript_PrintFullBox::
|
||||
|
||||
BattleScript_ActionSwitch::
|
||||
hpthresholds2 BS_ATTACKER
|
||||
copybyte sSAVED_BATTLER, gBattlerAttacker
|
||||
saveattacker
|
||||
printstring STRINGID_RETURNMON
|
||||
jumpifbattletype BATTLE_TYPE_DOUBLE, BattleScript_PursuitSwitchDmgSetMultihit
|
||||
setmultihit 1
|
||||
@ -5793,7 +5793,7 @@ BattleScript_DoSwitchOut::
|
||||
switchoutabilities BS_ATTACKER
|
||||
updatedynamax
|
||||
waitstate
|
||||
copybyte gBattlerAttacker, sSAVED_BATTLER
|
||||
restoreattacker
|
||||
returnatktoball
|
||||
waitstate
|
||||
drawpartystatussummary BS_ATTACKER
|
||||
@ -7820,7 +7820,7 @@ BattleScript_TryIntimidateHoldEffectsRet:
|
||||
return
|
||||
|
||||
BattleScript_IntimidateActivates::
|
||||
copybyte sSAVED_BATTLER, gBattlerTarget
|
||||
savetarget
|
||||
.if B_ABILITY_POP_UP == TRUE
|
||||
showabilitypopup BS_ATTACKER
|
||||
pause B_WAIT_TIME_LONG
|
||||
@ -7858,7 +7858,7 @@ BattleScript_IntimidateLoopIncrement:
|
||||
BattleScript_IntimidateEnd:
|
||||
copybyte sBATTLER, gBattlerAttacker
|
||||
destroyabilitypopup
|
||||
copybyte gBattlerTarget, sSAVED_BATTLER
|
||||
restoretarget
|
||||
pause B_WAIT_TIME_MED
|
||||
end3
|
||||
|
||||
@ -7891,7 +7891,7 @@ BattleScript_IntimidateInReverse:
|
||||
goto BattleScript_IntimidateLoopIncrement
|
||||
|
||||
BattleScript_SupersweetSyrupActivates::
|
||||
copybyte sSAVED_BATTLER, gBattlerTarget
|
||||
savetarget
|
||||
.if B_ABILITY_POP_UP == TRUE
|
||||
showabilitypopup BS_ATTACKER
|
||||
pause B_WAIT_TIME_LONG
|
||||
@ -7924,7 +7924,7 @@ BattleScript_SupersweetSyrupLoopIncrement:
|
||||
BattleScript_SupersweetSyrupEnd:
|
||||
copybyte sBATTLER, gBattlerAttacker
|
||||
destroyabilitypopup
|
||||
copybyte gBattlerTarget, sSAVED_BATTLER
|
||||
restoretarget
|
||||
pause B_WAIT_TIME_MED
|
||||
end3
|
||||
|
||||
@ -8315,7 +8315,7 @@ BattleScript_DazzlingProtected::
|
||||
attackstring
|
||||
ppreduce
|
||||
pause B_WAIT_TIME_SHORT
|
||||
call BattleScript_AbilityPopUp
|
||||
call BattleScript_AbilityPopUpScripting
|
||||
printstring STRINGID_POKEMONCANNOTUSEMOVE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
@ -8566,7 +8566,10 @@ BattleScript_FriskMsg::
|
||||
return
|
||||
|
||||
BattleScript_FriskActivates::
|
||||
tryfriskmsg BS_ATTACKER
|
||||
saveattacker
|
||||
copybyte gBattlerAttacker, sBATTLER
|
||||
tryfriskmsg BS_SCRIPTING
|
||||
restoreattacker
|
||||
end3
|
||||
|
||||
BattleScript_ImposterActivates::
|
||||
@ -9559,19 +9562,19 @@ BattleScript_RedCardIngrain:
|
||||
printstring STRINGID_PKMNANCHOREDITSELF
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
removeitem BS_SCRIPTING
|
||||
swapattackerwithtarget
|
||||
restoretarget
|
||||
return
|
||||
BattleScript_RedCardSuctionCups:
|
||||
printstring STRINGID_PKMNANCHORSITSELFWITH
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
removeitem BS_SCRIPTING
|
||||
swapattackerwithtarget
|
||||
restoretarget
|
||||
return
|
||||
BattleScript_RedCardDynamaxed:
|
||||
printstring STRINGID_MOVEBLOCKEDBYDYNAMAX
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
removeitem BS_SCRIPTING
|
||||
swapattackerwithtarget
|
||||
restoretarget
|
||||
return
|
||||
|
||||
BattleScript_EjectButtonActivates::
|
||||
|
||||
@ -359,10 +359,10 @@
|
||||
* Added missing `P_UPDATED_EVS` config that allows setting the EV yield changes across generations by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/3993
|
||||
* Added missing `P_UPDATED_EXP_YIELDS` config that allows setting the Experience yield changes across generations by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/3995
|
||||
* Added evolution methods that require custom trackers (`MON_DATA_EVOLUTION_TRACKER`) by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4087
|
||||
* `EVO_USE_MOVE_TWENTY_TIMES`:
|
||||
* `EVO_LEVEL_MOVE_TWENTY_TIMES`:
|
||||
* Stantler can now evolve into Wyrdeer by using Psyshield Bash 20 times.
|
||||
* Primeape can now evolve into Annihilape by using Rage Fist 20 times.
|
||||
* `EVO_RECOIL_DAMAGE_MALE`/`EVO_RECOIL_DAMAGE_FEMALE`
|
||||
* `EVO_LEVEL_RECOIL_DAMAGE_MALE`/`EVO_LEVEL_RECOIL_DAMAGE_FEMALE`
|
||||
* White-Striped Basculin can now evolve into Basculegion when leveling up after receiving 294HP of recoil damage and being the corresponding gender.
|
||||
* Added missing Paldean Wooper icon by @kittenchilly in https://github.com/rh-hideout/pokeemerald-expansion/pull/4260
|
||||
* Added missing data for placeholder Pokémon by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4281
|
||||
|
||||
@ -23,8 +23,8 @@
|
||||
* Fixed Exp. Candies ignoring hard caps.
|
||||
* Fixed Pokémon gaining 1 experience if they are at the level cap.
|
||||
* Fixed evolution tracker issues by @cawtds in https://github.com/rh-hideout/pokeemerald-expansion/pull/4503
|
||||
* `EVO_USE_MOVE_TWENTY_TIMES` no longer increases with every move.
|
||||
* `EVO_RECOIL_DAMAGE_MALE/FEMALE` is no longer updated twice than intended.
|
||||
* `EVO_LEVEL_MOVE_TWENTY_TIMES` no longer increases with every move.
|
||||
* `EVO_LEVEL_RECOIL_DAMAGE_MALE/FEMALE` is no longer updated twice than intended.
|
||||
|
||||
## ✨ Feature Branches ✨
|
||||
### ***TheXaman's HGSS Pokédex Plus***:
|
||||
|
||||
@ -92,9 +92,9 @@ void *AllocInternal(void *heapStart, u32 size, const char *location)
|
||||
{
|
||||
const char *location = MemBlockLocation(block);
|
||||
if (location)
|
||||
MgbaPrintf_("%s: %d bytes allocated", location, block->size);
|
||||
Test_MgbaPrintf("%s: %d bytes allocated", location, block->size);
|
||||
else
|
||||
MgbaPrintf_("<unknown>: %d bytes allocated", block->size);
|
||||
Test_MgbaPrintf("<unknown>: %d bytes allocated", block->size);
|
||||
}
|
||||
block = block->next;
|
||||
}
|
||||
|
||||
BIN
graphics/pokemon/terapagos/anim_front.png
Normal file
BIN
graphics/pokemon/terapagos/anim_front.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
graphics/pokemon/terapagos/back.png
Normal file
BIN
graphics/pokemon/terapagos/back.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 611 B |
19
graphics/pokemon/terapagos/normal.pal
Normal file
19
graphics/pokemon/terapagos/normal.pal
Normal file
@ -0,0 +1,19 @@
|
||||
JASC-PAL
|
||||
0100
|
||||
16
|
||||
152 208 160
|
||||
38 26 108
|
||||
49 34 133
|
||||
103 230 225
|
||||
60 76 160
|
||||
160 64 109
|
||||
228 103 181
|
||||
0 0 0
|
||||
115 162 235
|
||||
52 201 163
|
||||
76 244 204
|
||||
153 228 201
|
||||
230 244 173
|
||||
205 251 128
|
||||
63 50 194
|
||||
255 255 255
|
||||
19
graphics/pokemon/terapagos/shiny.pal
Normal file
19
graphics/pokemon/terapagos/shiny.pal
Normal file
@ -0,0 +1,19 @@
|
||||
JASC-PAL
|
||||
0100
|
||||
16
|
||||
152 208 160
|
||||
37 114 136
|
||||
66 151 189
|
||||
151 58 210
|
||||
63 209 230
|
||||
160 64 109
|
||||
234 243 49
|
||||
0 0 0
|
||||
218 32 48
|
||||
52 201 163
|
||||
76 244 204
|
||||
153 228 201
|
||||
230 244 173
|
||||
205 251 128
|
||||
63 50 194
|
||||
255 255 255
|
||||
BIN
graphics/pokemon/terapagos/terastal/anim_front.png
Normal file
BIN
graphics/pokemon/terapagos/terastal/anim_front.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
BIN
graphics/pokemon/terapagos/terastal/back.png
Normal file
BIN
graphics/pokemon/terapagos/terastal/back.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
19
graphics/pokemon/terapagos/terastal/normal.pal
Normal file
19
graphics/pokemon/terapagos/terastal/normal.pal
Normal file
@ -0,0 +1,19 @@
|
||||
JASC-PAL
|
||||
0100
|
||||
16
|
||||
152 208 160
|
||||
90 53 7
|
||||
42 121 78
|
||||
70 70 70
|
||||
215 38 89
|
||||
41 45 164
|
||||
77 151 158
|
||||
78 190 242
|
||||
170 172 227
|
||||
122 228 243
|
||||
147 245 227
|
||||
252 252 182
|
||||
255 255 255
|
||||
52 66 152
|
||||
0 200 255
|
||||
197 34 91
|
||||
19
graphics/pokemon/terapagos/terastal/shiny.pal
Normal file
19
graphics/pokemon/terapagos/terastal/shiny.pal
Normal file
@ -0,0 +1,19 @@
|
||||
JASC-PAL
|
||||
0100
|
||||
16
|
||||
152 208 160
|
||||
90 53 7
|
||||
42 121 78
|
||||
70 70 70
|
||||
215 38 89
|
||||
41 45 164
|
||||
77 151 158
|
||||
78 190 242
|
||||
170 172 227
|
||||
122 228 243
|
||||
147 245 227
|
||||
252 252 182
|
||||
255 255 255
|
||||
84 215 251
|
||||
255 0 0
|
||||
244 255 0
|
||||
BIN
graphics/types/none.png
Normal file
BIN
graphics/types/none.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 215 B |
@ -22,7 +22,7 @@ STARTERGFXDIR := graphics/starter_choose
|
||||
NAMINGGFXDIR := graphics/naming_screen
|
||||
SPINDAGFXDIR := graphics/pokemon/spinda/spots
|
||||
|
||||
types := normal fight flying poison ground rock bug ghost steel mystery fire water grass electric psychic ice dragon dark fairy stellar
|
||||
types := none normal fight flying poison ground rock bug ghost steel mystery fire water grass electric psychic ice dragon dark fairy stellar
|
||||
contest_types := cool beauty cute smart tough
|
||||
|
||||
### Tilesets ###
|
||||
|
||||
@ -738,7 +738,10 @@ struct BattleStruct
|
||||
u8 magnitudeBasePower;
|
||||
u8 presentBasePower;
|
||||
u8 roostTypes[MAX_BATTLERS_COUNT][2];
|
||||
u8 savedBattlerTarget;
|
||||
u8 savedBattlerTarget[5];
|
||||
u8 savedBattlerAttacker[5];
|
||||
u8 savedTargetCount:4;
|
||||
u8 savedAttackerCount:4;
|
||||
bool8 ateBoost[MAX_BATTLERS_COUNT];
|
||||
u8 activeAbilityPopUps; // as bits for each battler
|
||||
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler
|
||||
@ -1146,6 +1149,7 @@ extern u16 gLastThrownBall;
|
||||
extern u16 gBallToDisplay;
|
||||
extern bool8 gLastUsedBallMenuPresent;
|
||||
extern u8 gPartyCriticalHits[PARTY_SIZE];
|
||||
extern u8 gCategoryIconSpriteId;
|
||||
|
||||
static inline u32 GetBattlerPosition(u32 battler)
|
||||
{
|
||||
|
||||
@ -32,23 +32,21 @@
|
||||
#define BEST_DAMAGE_MOVE 1 // Move with the most amount of hits with the best accuracy/effect
|
||||
#define POWERFUL_STATUS_MOVE 10 // Moves with this score will be chosen over a move that faints target
|
||||
|
||||
// Temporary scores that are added together to determine a final score at the at of AI_CalcMoveEffectScore
|
||||
// Scores given in AI_CalcMoveEffectScore
|
||||
#define WEAK_EFFECT 1
|
||||
#define DECENT_EFFECT 2
|
||||
#define GOOD_EFFECT 4
|
||||
#define BEST_EFFECT 6
|
||||
|
||||
// AI_CalcMoveEffectScore final score
|
||||
#define NOT_GOOD_ENOUGH 0 // Not worth using over a damaging move
|
||||
#define GOOD_MOVE_EFFECTS 2 // Worth using over a damaging move
|
||||
#define PREFERRED_MOVE_EFFECTS 3 // Worth using over a damagin move and is better then DECENT_EFFECT
|
||||
#define BEST_MOVE_EFFECTS 4 // Best possible move effects. E.g. stat boosting moves that boost multiply moves
|
||||
#define GOOD_EFFECT 3
|
||||
#define BEST_EFFECT 4
|
||||
|
||||
// AI_TryToFaint
|
||||
#define FAST_KILL 6 // AI is faster and faints target
|
||||
#define SLOW_KILL 4 // AI is slower and faints target
|
||||
#define LAST_CHANCE 2 // AI faints to target. It should try and do damage with a priority move
|
||||
|
||||
// AI_Risky
|
||||
#define STRONG_RISKY_EFFECT 3
|
||||
#define AVERAGE_RISKY_EFFECT 2
|
||||
|
||||
#include "test_runner.h"
|
||||
|
||||
// Logs for debugging AI tests.
|
||||
|
||||
@ -3,15 +3,20 @@
|
||||
|
||||
#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE)
|
||||
|
||||
#define AI_STRIKES_FIRST(battlerAi, battlerDef, move)((AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER))
|
||||
// Roll boundaries used by AI when scoring. Doesn't affect actual damage dealt.
|
||||
#define MAX_ROLL_PERCENTAGE DMG_ROLL_PERCENT_HI
|
||||
#define MIN_ROLL_PERCENTAGE DMG_ROLL_PERCENT_LO
|
||||
#define DMG_ROLL_PERCENTAGE ((MAX_ROLL_PERCENTAGE + MIN_ROLL_PERCENTAGE + 1) / 2) // Controls the damage roll the AI sees for the default roll. By default the 9th roll is seen
|
||||
|
||||
enum
|
||||
{
|
||||
DMG_ROLL_LOWEST,
|
||||
DMG_ROLL_AVERAGE,
|
||||
DMG_ROLL_DEFAULT,
|
||||
DMG_ROLL_HIGHEST,
|
||||
};
|
||||
|
||||
bool32 AI_IsFaster(u32 battlerAi, u32 battlerDef, u32 move);
|
||||
bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 move);
|
||||
bool32 AI_RandLessThan(u32 val);
|
||||
bool32 IsAiVsAiBattle(void);
|
||||
bool32 BattlerHasAi(u32 battlerId);
|
||||
|
||||
940
include/battle_anim_scripts.h
Normal file
940
include/battle_anim_scripts.h
Normal file
@ -0,0 +1,940 @@
|
||||
#ifndef GUARD_BATTLE_ANIM_SCRIPTS_H
|
||||
#define GUARD_BATTLE_ANIM_SCRIPTS_H
|
||||
|
||||
extern const u8 Move_NONE[];
|
||||
extern const u8 Move_POUND[];
|
||||
extern const u8 Move_KARATE_CHOP[];
|
||||
extern const u8 Move_DOUBLE_SLAP[];
|
||||
extern const u8 Move_COMET_PUNCH[];
|
||||
extern const u8 Move_MEGA_PUNCH[];
|
||||
extern const u8 Move_PAY_DAY[];
|
||||
extern const u8 Move_FIRE_PUNCH[];
|
||||
extern const u8 Move_ICE_PUNCH[];
|
||||
extern const u8 Move_THUNDER_PUNCH[];
|
||||
extern const u8 Move_SCRATCH[];
|
||||
extern const u8 Move_VISE_GRIP[];
|
||||
extern const u8 Move_GUILLOTINE[];
|
||||
extern const u8 Move_RAZOR_WIND[];
|
||||
extern const u8 Move_SWORDS_DANCE[];
|
||||
extern const u8 Move_CUT[];
|
||||
extern const u8 Move_GUST[];
|
||||
extern const u8 Move_WING_ATTACK[];
|
||||
extern const u8 Move_WHIRLWIND[];
|
||||
extern const u8 Move_FLY[];
|
||||
extern const u8 Move_BIND[];
|
||||
extern const u8 Move_SLAM[];
|
||||
extern const u8 Move_VINE_WHIP[];
|
||||
extern const u8 Move_STOMP[];
|
||||
extern const u8 Move_DOUBLE_KICK[];
|
||||
extern const u8 Move_MEGA_KICK[];
|
||||
extern const u8 Move_JUMP_KICK[];
|
||||
extern const u8 Move_ROLLING_KICK[];
|
||||
extern const u8 Move_SAND_ATTACK[];
|
||||
extern const u8 Move_HEADBUTT[];
|
||||
extern const u8 Move_HORN_ATTACK[];
|
||||
extern const u8 Move_FURY_ATTACK[];
|
||||
extern const u8 Move_HORN_DRILL[];
|
||||
extern const u8 Move_TACKLE[];
|
||||
extern const u8 Move_BODY_SLAM[];
|
||||
extern const u8 Move_WRAP[];
|
||||
extern const u8 Move_TAKE_DOWN[];
|
||||
extern const u8 Move_THRASH[];
|
||||
extern const u8 Move_DOUBLE_EDGE[];
|
||||
extern const u8 Move_TAIL_WHIP[];
|
||||
extern const u8 Move_POISON_STING[];
|
||||
extern const u8 Move_TWINEEDLE[];
|
||||
extern const u8 Move_PIN_MISSILE[];
|
||||
extern const u8 Move_LEER[];
|
||||
extern const u8 Move_BITE[];
|
||||
extern const u8 Move_GROWL[];
|
||||
extern const u8 Move_ROAR[];
|
||||
extern const u8 Move_SING[];
|
||||
extern const u8 Move_SUPERSONIC[];
|
||||
extern const u8 Move_SONIC_BOOM[];
|
||||
extern const u8 Move_DISABLE[];
|
||||
extern const u8 Move_ACID[];
|
||||
extern const u8 Move_EMBER[];
|
||||
extern const u8 Move_FLAMETHROWER[];
|
||||
extern const u8 Move_MIST[];
|
||||
extern const u8 Move_WATER_GUN[];
|
||||
extern const u8 Move_HYDRO_PUMP[];
|
||||
extern const u8 Move_SURF[];
|
||||
extern const u8 Move_ICE_BEAM[];
|
||||
extern const u8 Move_BLIZZARD[];
|
||||
extern const u8 Move_PSYBEAM[];
|
||||
extern const u8 Move_BUBBLE_BEAM[];
|
||||
extern const u8 Move_AURORA_BEAM[];
|
||||
extern const u8 Move_HYPER_BEAM[];
|
||||
extern const u8 Move_PECK[];
|
||||
extern const u8 Move_DRILL_PECK[];
|
||||
extern const u8 Move_SUBMISSION[];
|
||||
extern const u8 Move_LOW_KICK[];
|
||||
extern const u8 Move_COUNTER[];
|
||||
extern const u8 Move_SEISMIC_TOSS[];
|
||||
extern const u8 Move_STRENGTH[];
|
||||
extern const u8 Move_ABSORB[];
|
||||
extern const u8 Move_MEGA_DRAIN[];
|
||||
extern const u8 Move_LEECH_SEED[];
|
||||
extern const u8 Move_GROWTH[];
|
||||
extern const u8 Move_RAZOR_LEAF[];
|
||||
extern const u8 Move_SOLAR_BEAM[];
|
||||
extern const u8 Move_POISON_POWDER[];
|
||||
extern const u8 Move_STUN_SPORE[];
|
||||
extern const u8 Move_SLEEP_POWDER[];
|
||||
extern const u8 Move_PETAL_DANCE[];
|
||||
extern const u8 Move_STRING_SHOT[];
|
||||
extern const u8 Move_DRAGON_RAGE[];
|
||||
extern const u8 Move_FIRE_SPIN[];
|
||||
extern const u8 Move_THUNDER_SHOCK[];
|
||||
extern const u8 Move_THUNDERBOLT[];
|
||||
extern const u8 Move_THUNDER_WAVE[];
|
||||
extern const u8 Move_THUNDER[];
|
||||
extern const u8 Move_ROCK_THROW[];
|
||||
extern const u8 Move_EARTHQUAKE[];
|
||||
extern const u8 Move_FISSURE[];
|
||||
extern const u8 Move_DIG[];
|
||||
extern const u8 Move_TOXIC[];
|
||||
extern const u8 Move_CONFUSION[];
|
||||
extern const u8 Move_PSYCHIC[];
|
||||
extern const u8 Move_HYPNOSIS[];
|
||||
extern const u8 Move_MEDITATE[];
|
||||
extern const u8 Move_AGILITY[];
|
||||
extern const u8 Move_QUICK_ATTACK[];
|
||||
extern const u8 Move_RAGE[];
|
||||
extern const u8 Move_TELEPORT[];
|
||||
extern const u8 Move_NIGHT_SHADE[];
|
||||
extern const u8 Move_MIMIC[];
|
||||
extern const u8 Move_SCREECH[];
|
||||
extern const u8 Move_DOUBLE_TEAM[];
|
||||
extern const u8 Move_RECOVER[];
|
||||
extern const u8 Move_HARDEN[];
|
||||
extern const u8 Move_MINIMIZE[];
|
||||
extern const u8 Move_SMOKESCREEN[];
|
||||
extern const u8 Move_CONFUSE_RAY[];
|
||||
extern const u8 Move_WITHDRAW[];
|
||||
extern const u8 Move_DEFENSE_CURL[];
|
||||
extern const u8 Move_BARRIER[];
|
||||
extern const u8 Move_LIGHT_SCREEN[];
|
||||
extern const u8 Move_HAZE[];
|
||||
extern const u8 Move_REFLECT[];
|
||||
extern const u8 Move_FOCUS_ENERGY[];
|
||||
extern const u8 Move_BIDE[];
|
||||
extern const u8 Move_METRONOME[];
|
||||
extern const u8 Move_MIRROR_MOVE[];
|
||||
extern const u8 Move_SELF_DESTRUCT[];
|
||||
extern const u8 Move_EGG_BOMB[];
|
||||
extern const u8 Move_LICK[];
|
||||
extern const u8 Move_SMOG[];
|
||||
extern const u8 Move_SLUDGE[];
|
||||
extern const u8 Move_BONE_CLUB[];
|
||||
extern const u8 Move_FIRE_BLAST[];
|
||||
extern const u8 Move_WATERFALL[];
|
||||
extern const u8 Move_CLAMP[];
|
||||
extern const u8 Move_SWIFT[];
|
||||
extern const u8 Move_SKULL_BASH[];
|
||||
extern const u8 Move_SPIKE_CANNON[];
|
||||
extern const u8 Move_CONSTRICT[];
|
||||
extern const u8 Move_AMNESIA[];
|
||||
extern const u8 Move_KINESIS[];
|
||||
extern const u8 Move_SOFT_BOILED[];
|
||||
extern const u8 Move_HIGH_JUMP_KICK[];
|
||||
extern const u8 Move_GLARE[];
|
||||
extern const u8 Move_DREAM_EATER[];
|
||||
extern const u8 Move_POISON_GAS[];
|
||||
extern const u8 Move_BARRAGE[];
|
||||
extern const u8 Move_LEECH_LIFE[];
|
||||
extern const u8 Move_LOVELY_KISS[];
|
||||
extern const u8 Move_SKY_ATTACK[];
|
||||
extern const u8 Move_TRANSFORM[];
|
||||
extern const u8 Move_BUBBLE[];
|
||||
extern const u8 Move_DIZZY_PUNCH[];
|
||||
extern const u8 Move_SPORE[];
|
||||
extern const u8 Move_FLASH[];
|
||||
extern const u8 Move_PSYWAVE[];
|
||||
extern const u8 Move_SPLASH[];
|
||||
extern const u8 Move_ACID_ARMOR[];
|
||||
extern const u8 Move_CRABHAMMER[];
|
||||
extern const u8 Move_EXPLOSION[];
|
||||
extern const u8 Move_FURY_SWIPES[];
|
||||
extern const u8 Move_BONEMERANG[];
|
||||
extern const u8 Move_REST[];
|
||||
extern const u8 Move_ROCK_SLIDE[];
|
||||
extern const u8 Move_HYPER_FANG[];
|
||||
extern const u8 Move_SHARPEN[];
|
||||
extern const u8 Move_CONVERSION[];
|
||||
extern const u8 Move_TRI_ATTACK[];
|
||||
extern const u8 Move_SUPER_FANG[];
|
||||
extern const u8 Move_SLASH[];
|
||||
extern const u8 Move_SUBSTITUTE[];
|
||||
extern const u8 Move_STRUGGLE[];
|
||||
extern const u8 Move_SKETCH[];
|
||||
extern const u8 Move_TRIPLE_KICK[];
|
||||
extern const u8 Move_THIEF[];
|
||||
extern const u8 Move_SPIDER_WEB[];
|
||||
extern const u8 Move_MIND_READER[];
|
||||
extern const u8 Move_NIGHTMARE[];
|
||||
extern const u8 Move_FLAME_WHEEL[];
|
||||
extern const u8 Move_SNORE[];
|
||||
extern const u8 Move_CURSE[];
|
||||
extern const u8 Move_FLAIL[];
|
||||
extern const u8 Move_CONVERSION_2[];
|
||||
extern const u8 Move_AEROBLAST[];
|
||||
extern const u8 Move_COTTON_SPORE[];
|
||||
extern const u8 Move_REVERSAL[];
|
||||
extern const u8 Move_SPITE[];
|
||||
extern const u8 Move_POWDER_SNOW[];
|
||||
extern const u8 Move_PROTECT[];
|
||||
extern const u8 Move_MACH_PUNCH[];
|
||||
extern const u8 Move_SCARY_FACE[];
|
||||
extern const u8 Move_FEINT_ATTACK[];
|
||||
extern const u8 Move_SWEET_KISS[];
|
||||
extern const u8 Move_BELLY_DRUM[];
|
||||
extern const u8 Move_SLUDGE_BOMB[];
|
||||
extern const u8 Move_MUD_SLAP[];
|
||||
extern const u8 Move_OCTAZOOKA[];
|
||||
extern const u8 Move_SPIKES[];
|
||||
extern const u8 Move_ZAP_CANNON[];
|
||||
extern const u8 Move_FORESIGHT[];
|
||||
extern const u8 Move_DESTINY_BOND[];
|
||||
extern const u8 Move_PERISH_SONG[];
|
||||
extern const u8 Move_ICY_WIND[];
|
||||
extern const u8 Move_DETECT[];
|
||||
extern const u8 Move_BONE_RUSH[];
|
||||
extern const u8 Move_LOCK_ON[];
|
||||
extern const u8 Move_OUTRAGE[];
|
||||
extern const u8 Move_SANDSTORM[];
|
||||
extern const u8 Move_GIGA_DRAIN[];
|
||||
extern const u8 Move_ENDURE[];
|
||||
extern const u8 Move_CHARM[];
|
||||
extern const u8 Move_ROLLOUT[];
|
||||
extern const u8 Move_FALSE_SWIPE[];
|
||||
extern const u8 Move_SWAGGER[];
|
||||
extern const u8 Move_MILK_DRINK[];
|
||||
extern const u8 Move_SPARK[];
|
||||
extern const u8 Move_FURY_CUTTER[];
|
||||
extern const u8 Move_STEEL_WING[];
|
||||
extern const u8 Move_MEAN_LOOK[];
|
||||
extern const u8 Move_ATTRACT[];
|
||||
extern const u8 Move_SLEEP_TALK[];
|
||||
extern const u8 Move_HEAL_BELL[];
|
||||
extern const u8 Move_RETURN[];
|
||||
extern const u8 Move_PRESENT[];
|
||||
extern const u8 Move_FRUSTRATION[];
|
||||
extern const u8 Move_SAFEGUARD[];
|
||||
extern const u8 Move_PAIN_SPLIT[];
|
||||
extern const u8 Move_SACRED_FIRE[];
|
||||
extern const u8 Move_MAGNITUDE[];
|
||||
extern const u8 Move_DYNAMIC_PUNCH[];
|
||||
extern const u8 Move_MEGAHORN[];
|
||||
extern const u8 Move_DRAGON_BREATH[];
|
||||
extern const u8 Move_BATON_PASS[];
|
||||
extern const u8 Move_ENCORE[];
|
||||
extern const u8 Move_PURSUIT[];
|
||||
extern const u8 Move_RAPID_SPIN[];
|
||||
extern const u8 Move_SWEET_SCENT[];
|
||||
extern const u8 Move_IRON_TAIL[];
|
||||
extern const u8 Move_METAL_CLAW[];
|
||||
extern const u8 Move_VITAL_THROW[];
|
||||
extern const u8 Move_MORNING_SUN[];
|
||||
extern const u8 Move_SYNTHESIS[];
|
||||
extern const u8 Move_MOONLIGHT[];
|
||||
extern const u8 Move_HIDDEN_POWER[];
|
||||
extern const u8 Move_CROSS_CHOP[];
|
||||
extern const u8 Move_TWISTER[];
|
||||
extern const u8 Move_RAIN_DANCE[];
|
||||
extern const u8 Move_SUNNY_DAY[];
|
||||
extern const u8 Move_CRUNCH[];
|
||||
extern const u8 Move_MIRROR_COAT[];
|
||||
extern const u8 Move_PSYCH_UP[];
|
||||
extern const u8 Move_EXTREME_SPEED[];
|
||||
extern const u8 Move_ANCIENT_POWER[];
|
||||
extern const u8 Move_SHADOW_BALL[];
|
||||
extern const u8 Move_FUTURE_SIGHT[];
|
||||
extern const u8 Move_ROCK_SMASH[];
|
||||
extern const u8 Move_WHIRLPOOL[];
|
||||
extern const u8 Move_BEAT_UP[];
|
||||
extern const u8 Move_FAKE_OUT[];
|
||||
extern const u8 Move_UPROAR[];
|
||||
extern const u8 Move_STOCKPILE[];
|
||||
extern const u8 Move_SPIT_UP[];
|
||||
extern const u8 Move_SWALLOW[];
|
||||
extern const u8 Move_HEAT_WAVE[];
|
||||
extern const u8 Move_HAIL[];
|
||||
extern const u8 Move_TORMENT[];
|
||||
extern const u8 Move_FLATTER[];
|
||||
extern const u8 Move_WILL_O_WISP[];
|
||||
extern const u8 Move_MEMENTO[];
|
||||
extern const u8 Move_FACADE[];
|
||||
extern const u8 Move_FOCUS_PUNCH[];
|
||||
extern const u8 Move_SMELLING_SALTS[];
|
||||
extern const u8 Move_FOLLOW_ME[];
|
||||
extern const u8 Move_NATURE_POWER[];
|
||||
extern const u8 Move_CHARGE[];
|
||||
extern const u8 Move_TAUNT[];
|
||||
extern const u8 Move_HELPING_HAND[];
|
||||
extern const u8 Move_TRICK[];
|
||||
extern const u8 Move_ROLE_PLAY[];
|
||||
extern const u8 Move_WISH[];
|
||||
extern const u8 Move_ASSIST[];
|
||||
extern const u8 Move_INGRAIN[];
|
||||
extern const u8 Move_SUPERPOWER[];
|
||||
extern const u8 Move_MAGIC_COAT[];
|
||||
extern const u8 Move_RECYCLE[];
|
||||
extern const u8 Move_REVENGE[];
|
||||
extern const u8 Move_BRICK_BREAK[];
|
||||
extern const u8 Move_YAWN[];
|
||||
extern const u8 Move_KNOCK_OFF[];
|
||||
extern const u8 Move_ENDEAVOR[];
|
||||
extern const u8 Move_ERUPTION[];
|
||||
extern const u8 Move_SKILL_SWAP[];
|
||||
extern const u8 Move_IMPRISON[];
|
||||
extern const u8 Move_REFRESH[];
|
||||
extern const u8 Move_GRUDGE[];
|
||||
extern const u8 Move_SNATCH[];
|
||||
extern const u8 Move_SECRET_POWER[];
|
||||
extern const u8 Move_DIVE[];
|
||||
extern const u8 Move_ARM_THRUST[];
|
||||
extern const u8 Move_CAMOUFLAGE[];
|
||||
extern const u8 Move_TAIL_GLOW[];
|
||||
extern const u8 Move_LUSTER_PURGE[];
|
||||
extern const u8 Move_MIST_BALL[];
|
||||
extern const u8 Move_FEATHER_DANCE[];
|
||||
extern const u8 Move_TEETER_DANCE[];
|
||||
extern const u8 Move_BLAZE_KICK[];
|
||||
extern const u8 Move_MUD_SPORT[];
|
||||
extern const u8 Move_ICE_BALL[];
|
||||
extern const u8 Move_NEEDLE_ARM[];
|
||||
extern const u8 Move_SLACK_OFF[];
|
||||
extern const u8 Move_HYPER_VOICE[];
|
||||
extern const u8 Move_POISON_FANG[];
|
||||
extern const u8 Move_CRUSH_CLAW[];
|
||||
extern const u8 Move_BLAST_BURN[];
|
||||
extern const u8 Move_HYDRO_CANNON[];
|
||||
extern const u8 Move_METEOR_MASH[];
|
||||
extern const u8 Move_ASTONISH[];
|
||||
extern const u8 Move_WEATHER_BALL[];
|
||||
extern const u8 Move_AROMATHERAPY[];
|
||||
extern const u8 Move_FAKE_TEARS[];
|
||||
extern const u8 Move_AIR_CUTTER[];
|
||||
extern const u8 Move_OVERHEAT[];
|
||||
extern const u8 Move_ODOR_SLEUTH[];
|
||||
extern const u8 Move_ROCK_TOMB[];
|
||||
extern const u8 Move_SILVER_WIND[];
|
||||
extern const u8 Move_METAL_SOUND[];
|
||||
extern const u8 Move_GRASS_WHISTLE[];
|
||||
extern const u8 Move_TICKLE[];
|
||||
extern const u8 Move_COSMIC_POWER[];
|
||||
extern const u8 Move_WATER_SPOUT[];
|
||||
extern const u8 Move_SIGNAL_BEAM[];
|
||||
extern const u8 Move_SHADOW_PUNCH[];
|
||||
extern const u8 Move_EXTRASENSORY[];
|
||||
extern const u8 Move_SKY_UPPERCUT[];
|
||||
extern const u8 Move_SAND_TOMB[];
|
||||
extern const u8 Move_SHEER_COLD[];
|
||||
extern const u8 Move_MUDDY_WATER[];
|
||||
extern const u8 Move_BULLET_SEED[];
|
||||
extern const u8 Move_AERIAL_ACE[];
|
||||
extern const u8 Move_ICICLE_SPEAR[];
|
||||
extern const u8 Move_IRON_DEFENSE[];
|
||||
extern const u8 Move_BLOCK[];
|
||||
extern const u8 Move_HOWL[];
|
||||
extern const u8 Move_DRAGON_CLAW[];
|
||||
extern const u8 Move_FRENZY_PLANT[];
|
||||
extern const u8 Move_BULK_UP[];
|
||||
extern const u8 Move_BOUNCE[];
|
||||
extern const u8 Move_MUD_SHOT[];
|
||||
extern const u8 Move_POISON_TAIL[];
|
||||
extern const u8 Move_COVET[];
|
||||
extern const u8 Move_VOLT_TACKLE[];
|
||||
extern const u8 Move_MAGICAL_LEAF[];
|
||||
extern const u8 Move_WATER_SPORT[];
|
||||
extern const u8 Move_CALM_MIND[];
|
||||
extern const u8 Move_LEAF_BLADE[];
|
||||
extern const u8 Move_DRAGON_DANCE[];
|
||||
extern const u8 Move_ROCK_BLAST[];
|
||||
extern const u8 Move_SHOCK_WAVE[];
|
||||
extern const u8 Move_WATER_PULSE[];
|
||||
extern const u8 Move_DOOM_DESIRE[];
|
||||
extern const u8 Move_PSYCHO_BOOST[];
|
||||
extern const u8 Move_ROOST[];
|
||||
extern const u8 Move_GRAVITY[];
|
||||
extern const u8 Move_MIRACLE_EYE[];
|
||||
extern const u8 Move_WAKE_UP_SLAP[];
|
||||
extern const u8 Move_HAMMER_ARM[];
|
||||
extern const u8 Move_GYRO_BALL[];
|
||||
extern const u8 Move_HEALING_WISH[];
|
||||
extern const u8 Move_BRINE[];
|
||||
extern const u8 Move_NATURAL_GIFT[];
|
||||
extern const u8 Move_FEINT[];
|
||||
extern const u8 Move_PLUCK[];
|
||||
extern const u8 Move_TAILWIND[];
|
||||
extern const u8 Move_ACUPRESSURE[];
|
||||
extern const u8 Move_METAL_BURST[];
|
||||
extern const u8 Move_U_TURN[];
|
||||
extern const u8 Move_CLOSE_COMBAT[];
|
||||
extern const u8 Move_PAYBACK[];
|
||||
extern const u8 Move_ASSURANCE[];
|
||||
extern const u8 Move_EMBARGO[];
|
||||
extern const u8 Move_FLING[];
|
||||
extern const u8 Move_PSYCHO_SHIFT[];
|
||||
extern const u8 Move_TRUMP_CARD[];
|
||||
extern const u8 Move_HEAL_BLOCK[];
|
||||
extern const u8 Move_WRING_OUT[];
|
||||
extern const u8 Move_POWER_TRICK[];
|
||||
extern const u8 Move_GASTRO_ACID[];
|
||||
extern const u8 Move_LUCKY_CHANT[];
|
||||
extern const u8 Move_ME_FIRST[];
|
||||
extern const u8 Move_COPYCAT[];
|
||||
extern const u8 Move_POWER_SWAP[];
|
||||
extern const u8 Move_GUARD_SWAP[];
|
||||
extern const u8 Move_PUNISHMENT[];
|
||||
extern const u8 Move_LAST_RESORT[];
|
||||
extern const u8 Move_WORRY_SEED[];
|
||||
extern const u8 Move_SUCKER_PUNCH[];
|
||||
extern const u8 Move_TOXIC_SPIKES[];
|
||||
extern const u8 Move_HEART_SWAP[];
|
||||
extern const u8 Move_AQUA_RING[];
|
||||
extern const u8 Move_MAGNET_RISE[];
|
||||
extern const u8 Move_FLARE_BLITZ[];
|
||||
extern const u8 Move_FORCE_PALM[];
|
||||
extern const u8 Move_AURA_SPHERE[];
|
||||
extern const u8 Move_ROCK_POLISH[];
|
||||
extern const u8 Move_POISON_JAB[];
|
||||
extern const u8 Move_DARK_PULSE[];
|
||||
extern const u8 Move_NIGHT_SLASH[];
|
||||
extern const u8 Move_AQUA_TAIL[];
|
||||
extern const u8 Move_SEED_BOMB[];
|
||||
extern const u8 Move_AIR_SLASH[];
|
||||
extern const u8 Move_X_SCISSOR[];
|
||||
extern const u8 Move_BUG_BUZZ[];
|
||||
extern const u8 Move_DRAGON_PULSE[];
|
||||
extern const u8 Move_DRAGON_RUSH[];
|
||||
extern const u8 Move_POWER_GEM[];
|
||||
extern const u8 Move_DRAIN_PUNCH[];
|
||||
extern const u8 Move_VACUUM_WAVE[];
|
||||
extern const u8 Move_FOCUS_BLAST[];
|
||||
extern const u8 Move_ENERGY_BALL[];
|
||||
extern const u8 Move_BRAVE_BIRD[];
|
||||
extern const u8 Move_EARTH_POWER[];
|
||||
extern const u8 Move_SWITCHEROO[];
|
||||
extern const u8 Move_GIGA_IMPACT[];
|
||||
extern const u8 Move_NASTY_PLOT[];
|
||||
extern const u8 Move_BULLET_PUNCH[];
|
||||
extern const u8 Move_AVALANCHE[];
|
||||
extern const u8 Move_ICE_SHARD[];
|
||||
extern const u8 Move_SHADOW_CLAW[];
|
||||
extern const u8 Move_THUNDER_FANG[];
|
||||
extern const u8 Move_ICE_FANG[];
|
||||
extern const u8 Move_FIRE_FANG[];
|
||||
extern const u8 Move_SHADOW_SNEAK[];
|
||||
extern const u8 Move_MUD_BOMB[];
|
||||
extern const u8 Move_PSYCHO_CUT[];
|
||||
extern const u8 Move_ZEN_HEADBUTT[];
|
||||
extern const u8 Move_MIRROR_SHOT[];
|
||||
extern const u8 Move_FLASH_CANNON[];
|
||||
extern const u8 Move_ROCK_CLIMB[];
|
||||
extern const u8 Move_DEFOG[];
|
||||
extern const u8 Move_TRICK_ROOM[];
|
||||
extern const u8 Move_DRACO_METEOR[];
|
||||
extern const u8 Move_DISCHARGE[];
|
||||
extern const u8 Move_LAVA_PLUME[];
|
||||
extern const u8 Move_LEAF_STORM[];
|
||||
extern const u8 Move_POWER_WHIP[];
|
||||
extern const u8 Move_ROCK_WRECKER[];
|
||||
extern const u8 Move_CROSS_POISON[];
|
||||
extern const u8 Move_GUNK_SHOT[];
|
||||
extern const u8 Move_IRON_HEAD[];
|
||||
extern const u8 Move_MAGNET_BOMB[];
|
||||
extern const u8 Move_STONE_EDGE[];
|
||||
extern const u8 Move_CAPTIVATE[];
|
||||
extern const u8 Move_STEALTH_ROCK[];
|
||||
extern const u8 Move_GRASS_KNOT[];
|
||||
extern const u8 Move_CHATTER[];
|
||||
extern const u8 Move_JUDGMENT[];
|
||||
extern const u8 Move_BUG_BITE[];
|
||||
extern const u8 Move_CHARGE_BEAM[];
|
||||
extern const u8 Move_WOOD_HAMMER[];
|
||||
extern const u8 Move_AQUA_JET[];
|
||||
extern const u8 Move_ATTACK_ORDER[];
|
||||
extern const u8 Move_DEFEND_ORDER[];
|
||||
extern const u8 Move_HEAL_ORDER[];
|
||||
extern const u8 Move_HEAD_SMASH[];
|
||||
extern const u8 Move_DOUBLE_HIT[];
|
||||
extern const u8 Move_ROAR_OF_TIME[];
|
||||
extern const u8 Move_SPACIAL_REND[];
|
||||
extern const u8 Move_LUNAR_DANCE[];
|
||||
extern const u8 Move_CRUSH_GRIP[];
|
||||
extern const u8 Move_MAGMA_STORM[];
|
||||
extern const u8 Move_DARK_VOID[];
|
||||
extern const u8 Move_SEED_FLARE[];
|
||||
extern const u8 Move_OMINOUS_WIND[];
|
||||
extern const u8 Move_SHADOW_FORCE[];
|
||||
extern const u8 Move_HONE_CLAWS[];
|
||||
extern const u8 Move_WIDE_GUARD[];
|
||||
extern const u8 Move_GUARD_SPLIT[];
|
||||
extern const u8 Move_POWER_SPLIT[];
|
||||
extern const u8 Move_WONDER_ROOM[];
|
||||
extern const u8 Move_PSYSHOCK[];
|
||||
extern const u8 Move_VENOSHOCK[];
|
||||
extern const u8 Move_AUTOTOMIZE[];
|
||||
extern const u8 Move_RAGE_POWDER[];
|
||||
extern const u8 Move_TELEKINESIS[];
|
||||
extern const u8 Move_MAGIC_ROOM[];
|
||||
extern const u8 Move_SMACK_DOWN[];
|
||||
extern const u8 Move_STORM_THROW[];
|
||||
extern const u8 Move_FLAME_BURST[];
|
||||
extern const u8 Move_SLUDGE_WAVE[];
|
||||
extern const u8 Move_QUIVER_DANCE[];
|
||||
extern const u8 Move_HEAVY_SLAM[];
|
||||
extern const u8 Move_SYNCHRONOISE[];
|
||||
extern const u8 Move_ELECTRO_BALL[];
|
||||
extern const u8 Move_SOAK[];
|
||||
extern const u8 Move_FLAME_CHARGE[];
|
||||
extern const u8 Move_COIL[];
|
||||
extern const u8 Move_LOW_SWEEP[];
|
||||
extern const u8 Move_ACID_SPRAY[];
|
||||
extern const u8 Move_FOUL_PLAY[];
|
||||
extern const u8 Move_SIMPLE_BEAM[];
|
||||
extern const u8 Move_ENTRAINMENT[];
|
||||
extern const u8 Move_AFTER_YOU[];
|
||||
extern const u8 Move_ROUND[];
|
||||
extern const u8 Move_ECHOED_VOICE[];
|
||||
extern const u8 Move_CHIP_AWAY[];
|
||||
extern const u8 Move_CLEAR_SMOG[];
|
||||
extern const u8 Move_STORED_POWER[];
|
||||
extern const u8 Move_QUICK_GUARD[];
|
||||
extern const u8 Move_ALLY_SWITCH[];
|
||||
extern const u8 Move_SCALD[];
|
||||
extern const u8 Move_SHELL_SMASH[];
|
||||
extern const u8 Move_HEAL_PULSE[];
|
||||
extern const u8 Move_HEX[];
|
||||
extern const u8 Move_SKY_DROP[];
|
||||
extern const u8 Move_SHIFT_GEAR[];
|
||||
extern const u8 Move_CIRCLE_THROW[];
|
||||
extern const u8 Move_INCINERATE[];
|
||||
extern const u8 Move_QUASH[];
|
||||
extern const u8 Move_ACROBATICS[];
|
||||
extern const u8 Move_REFLECT_TYPE[];
|
||||
extern const u8 Move_RETALIATE[];
|
||||
extern const u8 Move_FINAL_GAMBIT[];
|
||||
extern const u8 Move_BESTOW[];
|
||||
extern const u8 Move_INFERNO[];
|
||||
extern const u8 Move_WATER_PLEDGE[];
|
||||
extern const u8 Move_FIRE_PLEDGE[];
|
||||
extern const u8 Move_GRASS_PLEDGE[];
|
||||
extern const u8 Move_VOLT_SWITCH[];
|
||||
extern const u8 Move_STRUGGLE_BUG[];
|
||||
extern const u8 Move_BULLDOZE[];
|
||||
extern const u8 Move_FROST_BREATH[];
|
||||
extern const u8 Move_DRAGON_TAIL[];
|
||||
extern const u8 Move_WORK_UP[];
|
||||
extern const u8 Move_ELECTROWEB[];
|
||||
extern const u8 Move_WILD_CHARGE[];
|
||||
extern const u8 Move_DRILL_RUN[];
|
||||
extern const u8 Move_DUAL_CHOP[];
|
||||
extern const u8 Move_HEART_STAMP[];
|
||||
extern const u8 Move_HORN_LEECH[];
|
||||
extern const u8 Move_SACRED_SWORD[];
|
||||
extern const u8 Move_RAZOR_SHELL[];
|
||||
extern const u8 Move_HEAT_CRASH[];
|
||||
extern const u8 Move_LEAF_TORNADO[];
|
||||
extern const u8 Move_STEAMROLLER[];
|
||||
extern const u8 Move_COTTON_GUARD[];
|
||||
extern const u8 Move_NIGHT_DAZE[];
|
||||
extern const u8 Move_PSYSTRIKE[];
|
||||
extern const u8 Move_TAIL_SLAP[];
|
||||
extern const u8 Move_HURRICANE[];
|
||||
extern const u8 Move_HEAD_CHARGE[];
|
||||
extern const u8 Move_GEAR_GRIND[];
|
||||
extern const u8 Move_SEARING_SHOT[];
|
||||
extern const u8 Move_TECHNO_BLAST[];
|
||||
extern const u8 Move_RELIC_SONG[];
|
||||
extern const u8 Move_SECRET_SWORD[];
|
||||
extern const u8 Move_GLACIATE[];
|
||||
extern const u8 Move_BOLT_STRIKE[];
|
||||
extern const u8 Move_BLUE_FLARE[];
|
||||
extern const u8 Move_FIERY_DANCE[];
|
||||
extern const u8 Move_FREEZE_SHOCK[];
|
||||
extern const u8 Move_ICE_BURN[];
|
||||
extern const u8 Move_SNARL[];
|
||||
extern const u8 Move_ICICLE_CRASH[];
|
||||
extern const u8 Move_V_CREATE[];
|
||||
extern const u8 Move_FUSION_FLARE[];
|
||||
extern const u8 Move_FUSION_BOLT[];
|
||||
extern const u8 Move_FLYING_PRESS[];
|
||||
extern const u8 Move_MAT_BLOCK[];
|
||||
extern const u8 Move_BELCH[];
|
||||
extern const u8 Move_ROTOTILLER[];
|
||||
extern const u8 Move_STICKY_WEB[];
|
||||
extern const u8 Move_FELL_STINGER[];
|
||||
extern const u8 Move_PHANTOM_FORCE[];
|
||||
extern const u8 Move_TRICK_OR_TREAT[];
|
||||
extern const u8 Move_NOBLE_ROAR[];
|
||||
extern const u8 Move_ION_DELUGE[];
|
||||
extern const u8 Move_PARABOLIC_CHARGE[];
|
||||
extern const u8 Move_FORESTS_CURSE[];
|
||||
extern const u8 Move_PETAL_BLIZZARD[];
|
||||
extern const u8 Move_FREEZE_DRY[];
|
||||
extern const u8 Move_DISARMING_VOICE[];
|
||||
extern const u8 Move_PARTING_SHOT[];
|
||||
extern const u8 Move_TOPSY_TURVY[];
|
||||
extern const u8 Move_DRAINING_KISS[];
|
||||
extern const u8 Move_CRAFTY_SHIELD[];
|
||||
extern const u8 Move_FLOWER_SHIELD[];
|
||||
extern const u8 Move_GRASSY_TERRAIN[];
|
||||
extern const u8 Move_MISTY_TERRAIN[];
|
||||
extern const u8 Move_ELECTRIFY[];
|
||||
extern const u8 Move_PLAY_ROUGH[];
|
||||
extern const u8 Move_FAIRY_WIND[];
|
||||
extern const u8 Move_MOONBLAST[];
|
||||
extern const u8 Move_BOOMBURST[];
|
||||
extern const u8 Move_FAIRY_LOCK[];
|
||||
extern const u8 Move_KINGS_SHIELD[];
|
||||
extern const u8 Move_PLAY_NICE[];
|
||||
extern const u8 Move_CONFIDE[];
|
||||
extern const u8 Move_DIAMOND_STORM[];
|
||||
extern const u8 Move_STEAM_ERUPTION[];
|
||||
extern const u8 Move_HYPERSPACE_HOLE[];
|
||||
extern const u8 Move_WATER_SHURIKEN[];
|
||||
extern const u8 Move_MYSTICAL_FIRE[];
|
||||
extern const u8 Move_SPIKY_SHIELD[];
|
||||
extern const u8 Move_AROMATIC_MIST[];
|
||||
extern const u8 Move_EERIE_IMPULSE[];
|
||||
extern const u8 Move_VENOM_DRENCH[];
|
||||
extern const u8 Move_POWDER[];
|
||||
extern const u8 Move_GEOMANCY[];
|
||||
extern const u8 Move_MAGNETIC_FLUX[];
|
||||
extern const u8 Move_HAPPY_HOUR[];
|
||||
extern const u8 Move_ELECTRIC_TERRAIN[];
|
||||
extern const u8 Move_DAZZLING_GLEAM[];
|
||||
extern const u8 Move_CELEBRATE[];
|
||||
extern const u8 Move_HOLD_HANDS[];
|
||||
extern const u8 Move_BABY_DOLL_EYES[];
|
||||
extern const u8 Move_NUZZLE[];
|
||||
extern const u8 Move_HOLD_BACK[];
|
||||
extern const u8 Move_INFESTATION[];
|
||||
extern const u8 Move_POWER_UP_PUNCH[];
|
||||
extern const u8 Move_OBLIVION_WING[];
|
||||
extern const u8 Move_THOUSAND_ARROWS[];
|
||||
extern const u8 Move_THOUSAND_WAVES[];
|
||||
extern const u8 Move_LANDS_WRATH[];
|
||||
extern const u8 Move_LIGHT_OF_RUIN[];
|
||||
extern const u8 Move_ORIGIN_PULSE[];
|
||||
extern const u8 Move_PRECIPICE_BLADES[];
|
||||
extern const u8 Move_DRAGON_ASCENT[];
|
||||
extern const u8 Move_HYPERSPACE_FURY[];
|
||||
extern const u8 Move_SHORE_UP[];
|
||||
extern const u8 Move_FIRST_IMPRESSION[];
|
||||
extern const u8 Move_BANEFUL_BUNKER[];
|
||||
extern const u8 Move_SPIRIT_SHACKLE[];
|
||||
extern const u8 Move_DARKEST_LARIAT[];
|
||||
extern const u8 Move_SPARKLING_ARIA[];
|
||||
extern const u8 Move_ICE_HAMMER[];
|
||||
extern const u8 Move_FLORAL_HEALING[];
|
||||
extern const u8 Move_HIGH_HORSEPOWER[];
|
||||
extern const u8 Move_STRENGTH_SAP[];
|
||||
extern const u8 Move_SOLAR_BLADE[];
|
||||
extern const u8 Move_LEAFAGE[];
|
||||
extern const u8 Move_SPOTLIGHT[];
|
||||
extern const u8 Move_TOXIC_THREAD[];
|
||||
extern const u8 Move_LASER_FOCUS[];
|
||||
extern const u8 Move_GEAR_UP[];
|
||||
extern const u8 Move_THROAT_CHOP[];
|
||||
extern const u8 Move_POLLEN_PUFF[];
|
||||
extern const u8 Move_ANCHOR_SHOT[];
|
||||
extern const u8 Move_PSYCHIC_TERRAIN[];
|
||||
extern const u8 Move_LUNGE[];
|
||||
extern const u8 Move_FIRE_LASH[];
|
||||
extern const u8 Move_POWER_TRIP[];
|
||||
extern const u8 Move_BURN_UP[];
|
||||
extern const u8 Move_SPEED_SWAP[];
|
||||
extern const u8 Move_SMART_STRIKE[];
|
||||
extern const u8 Move_PURIFY[];
|
||||
extern const u8 Move_REVELATION_DANCE[];
|
||||
extern const u8 Move_CORE_ENFORCER[];
|
||||
extern const u8 Move_TROP_KICK[];
|
||||
extern const u8 Move_INSTRUCT[];
|
||||
extern const u8 Move_BEAK_BLAST[];
|
||||
extern const u8 Move_CLANGING_SCALES[];
|
||||
extern const u8 Move_DRAGON_HAMMER[];
|
||||
extern const u8 Move_BRUTAL_SWING[];
|
||||
extern const u8 Move_AURORA_VEIL[];
|
||||
extern const u8 Move_SHELL_TRAP[];
|
||||
extern const u8 Move_FLEUR_CANNON[];
|
||||
extern const u8 Move_PSYCHIC_FANGS[];
|
||||
extern const u8 Move_STOMPING_TANTRUM[];
|
||||
extern const u8 Move_SHADOW_BONE[];
|
||||
extern const u8 Move_ACCELEROCK[];
|
||||
extern const u8 Move_LIQUIDATION[];
|
||||
extern const u8 Move_PRISMATIC_LASER[];
|
||||
extern const u8 Move_SPECTRAL_THIEF[];
|
||||
extern const u8 Move_SUNSTEEL_STRIKE[];
|
||||
extern const u8 Move_MOONGEIST_BEAM[];
|
||||
extern const u8 Move_TEARFUL_LOOK[];
|
||||
extern const u8 Move_ZING_ZAP[];
|
||||
extern const u8 Move_NATURES_MADNESS[];
|
||||
extern const u8 Move_MULTI_ATTACK[];
|
||||
extern const u8 Move_MIND_BLOWN[];
|
||||
extern const u8 Move_PLASMA_FISTS[];
|
||||
extern const u8 Move_PHOTON_GEYSER[];
|
||||
extern const u8 Move_ZIPPY_ZAP[];
|
||||
extern const u8 Move_SPLISHY_SPLASH[];
|
||||
extern const u8 Move_FLOATY_FALL[];
|
||||
extern const u8 Move_PIKA_PAPOW[];
|
||||
extern const u8 Move_BOUNCY_BUBBLE[];
|
||||
extern const u8 Move_BUZZY_BUZZ[];
|
||||
extern const u8 Move_SIZZLY_SLIDE[];
|
||||
extern const u8 Move_GLITZY_GLOW[];
|
||||
extern const u8 Move_BADDY_BAD[];
|
||||
extern const u8 Move_SAPPY_SEED[];
|
||||
extern const u8 Move_FREEZY_FROST[];
|
||||
extern const u8 Move_SPARKLY_SWIRL[];
|
||||
extern const u8 Move_VEEVEE_VOLLEY[];
|
||||
extern const u8 Move_DOUBLE_IRON_BASH[];
|
||||
extern const u8 Move_DYNAMAX_CANNON[];
|
||||
extern const u8 Move_SNIPE_SHOT[];
|
||||
extern const u8 Move_JAW_LOCK[];
|
||||
extern const u8 Move_STUFF_CHEEKS[];
|
||||
extern const u8 Move_NO_RETREAT[];
|
||||
extern const u8 Move_TAR_SHOT[];
|
||||
extern const u8 Move_MAGIC_POWDER[];
|
||||
extern const u8 Move_DRAGON_DARTS[];
|
||||
extern const u8 Move_TEATIME[];
|
||||
extern const u8 Move_OCTOLOCK[];
|
||||
extern const u8 Move_BOLT_BEAK[];
|
||||
extern const u8 Move_FISHIOUS_REND[];
|
||||
extern const u8 Move_COURT_CHANGE[];
|
||||
extern const u8 Move_CLANGOROUS_SOUL[];
|
||||
extern const u8 Move_BODY_PRESS[];
|
||||
extern const u8 Move_DECORATE[];
|
||||
extern const u8 Move_DRUM_BEATING[];
|
||||
extern const u8 Move_SNAP_TRAP[];
|
||||
extern const u8 Move_PYRO_BALL[];
|
||||
extern const u8 Move_BEHEMOTH_BLADE[];
|
||||
extern const u8 Move_BEHEMOTH_BASH[];
|
||||
extern const u8 Move_AURA_WHEEL[];
|
||||
extern const u8 Move_BREAKING_SWIPE[];
|
||||
extern const u8 Move_BRANCH_POKE[];
|
||||
extern const u8 Move_OVERDRIVE[];
|
||||
extern const u8 Move_APPLE_ACID[];
|
||||
extern const u8 Move_GRAV_APPLE[];
|
||||
extern const u8 Move_SPIRIT_BREAK[];
|
||||
extern const u8 Move_STRANGE_STEAM[];
|
||||
extern const u8 Move_LIFE_DEW[];
|
||||
extern const u8 Move_OBSTRUCT[];
|
||||
extern const u8 Move_FALSE_SURRENDER[];
|
||||
extern const u8 Move_METEOR_ASSAULT[];
|
||||
extern const u8 Move_ETERNABEAM[];
|
||||
extern const u8 Move_STEEL_BEAM[];
|
||||
extern const u8 Move_EXPANDING_FORCE[];
|
||||
extern const u8 Move_STEEL_ROLLER[];
|
||||
extern const u8 Move_SCALE_SHOT[];
|
||||
extern const u8 Move_METEOR_BEAM[];
|
||||
extern const u8 Move_SHELL_SIDE_ARM[];
|
||||
extern const u8 Move_MISTY_EXPLOSION[];
|
||||
extern const u8 Move_GRASSY_GLIDE[];
|
||||
extern const u8 Move_RISING_VOLTAGE[];
|
||||
extern const u8 Move_TERRAIN_PULSE[];
|
||||
extern const u8 Move_SKITTER_SMACK[];
|
||||
extern const u8 Move_BURNING_JEALOUSY[];
|
||||
extern const u8 Move_LASH_OUT[];
|
||||
extern const u8 Move_POLTERGEIST[];
|
||||
extern const u8 Move_CORROSIVE_GAS[];
|
||||
extern const u8 Move_COACHING[];
|
||||
extern const u8 Move_FLIP_TURN[];
|
||||
extern const u8 Move_TRIPLE_AXEL[];
|
||||
extern const u8 Move_DUAL_WINGBEAT[];
|
||||
extern const u8 Move_SCORCHING_SANDS[];
|
||||
extern const u8 Move_JUNGLE_HEALING[];
|
||||
extern const u8 Move_WICKED_BLOW[];
|
||||
extern const u8 Move_SURGING_STRIKES[];
|
||||
extern const u8 Move_THUNDER_CAGE[];
|
||||
extern const u8 Move_DRAGON_ENERGY[];
|
||||
extern const u8 Move_FREEZING_GLARE[];
|
||||
extern const u8 Move_FIERY_WRATH[];
|
||||
extern const u8 Move_THUNDEROUS_KICK[];
|
||||
extern const u8 Move_GLACIAL_LANCE[];
|
||||
extern const u8 Move_ASTRAL_BARRAGE[];
|
||||
extern const u8 Move_EERIE_SPELL[];
|
||||
extern const u8 Move_DIRE_CLAW[];
|
||||
extern const u8 Move_PSYSHIELD_BASH[];
|
||||
extern const u8 Move_POWER_SHIFT[];
|
||||
extern const u8 Move_STONE_AXE[];
|
||||
extern const u8 Move_SPRINGTIDE_STORM[];
|
||||
extern const u8 Move_MYSTICAL_POWER[];
|
||||
extern const u8 Move_RAGING_FURY[];
|
||||
extern const u8 Move_WAVE_CRASH[];
|
||||
extern const u8 Move_CHLOROBLAST[];
|
||||
extern const u8 Move_MOUNTAIN_GALE[];
|
||||
extern const u8 Move_VICTORY_DANCE[];
|
||||
extern const u8 Move_HEADLONG_RUSH[];
|
||||
extern const u8 Move_BARB_BARRAGE[];
|
||||
extern const u8 Move_ESPER_WING[];
|
||||
extern const u8 Move_BITTER_MALICE[];
|
||||
extern const u8 Move_SHELTER[];
|
||||
extern const u8 Move_TRIPLE_ARROWS[];
|
||||
extern const u8 Move_INFERNAL_PARADE[];
|
||||
extern const u8 Move_CEASELESS_EDGE[];
|
||||
extern const u8 Move_BLEAKWIND_STORM[];
|
||||
extern const u8 Move_WILDBOLT_STORM[];
|
||||
extern const u8 Move_SANDSEAR_STORM[];
|
||||
extern const u8 Move_LUNAR_BLESSING[];
|
||||
extern const u8 Move_TAKE_HEART[];
|
||||
extern const u8 Move_TERA_BLAST[];
|
||||
extern const u8 Move_SILK_TRAP[];
|
||||
extern const u8 Move_AXE_KICK[];
|
||||
extern const u8 Move_LAST_RESPECTS[];
|
||||
extern const u8 Move_LUMINA_CRASH[];
|
||||
extern const u8 Move_ORDER_UP[];
|
||||
extern const u8 Move_JET_PUNCH[];
|
||||
extern const u8 Move_SPICY_EXTRACT[];
|
||||
extern const u8 Move_SPIN_OUT[];
|
||||
extern const u8 Move_POPULATION_BOMB[];
|
||||
extern const u8 Move_ICE_SPINNER[];
|
||||
extern const u8 Move_GLAIVE_RUSH[];
|
||||
extern const u8 Move_REVIVAL_BLESSING[];
|
||||
extern const u8 Move_SALT_CURE[];
|
||||
extern const u8 Move_TRIPLE_DIVE[];
|
||||
extern const u8 Move_MORTAL_SPIN[];
|
||||
extern const u8 Move_DOODLE[];
|
||||
extern const u8 Move_FILLET_AWAY[];
|
||||
extern const u8 Move_KOWTOW_CLEAVE[];
|
||||
extern const u8 Move_FLOWER_TRICK[];
|
||||
extern const u8 Move_TORCH_SONG[];
|
||||
extern const u8 Move_AQUA_STEP[];
|
||||
extern const u8 Move_RAGING_BULL[];
|
||||
extern const u8 Move_MAKE_IT_RAIN[];
|
||||
extern const u8 Move_RUINATION[];
|
||||
extern const u8 Move_COLLISION_COURSE[];
|
||||
extern const u8 Move_ELECTRO_DRIFT[];
|
||||
extern const u8 Move_SHED_TAIL[];
|
||||
extern const u8 Move_CHILLY_RECEPTION[];
|
||||
extern const u8 Move_TIDY_UP[];
|
||||
extern const u8 Move_SNOWSCAPE[];
|
||||
extern const u8 Move_POUNCE[];
|
||||
extern const u8 Move_TRAILBLAZE[];
|
||||
extern const u8 Move_CHILLING_WATER[];
|
||||
extern const u8 Move_HYPER_DRILL[];
|
||||
extern const u8 Move_TWIN_BEAM[];
|
||||
extern const u8 Move_RAGE_FIST[];
|
||||
extern const u8 Move_ARMOR_CANNON[];
|
||||
extern const u8 Move_BITTER_BLADE[];
|
||||
extern const u8 Move_DOUBLE_SHOCK[];
|
||||
extern const u8 Move_GIGATON_HAMMER[];
|
||||
extern const u8 Move_COMEUPPANCE[];
|
||||
extern const u8 Move_AQUA_CUTTER[];
|
||||
extern const u8 Move_BLAZING_TORQUE[];
|
||||
extern const u8 Move_WICKED_TORQUE[];
|
||||
extern const u8 Move_NOXIOUS_TORQUE[];
|
||||
extern const u8 Move_COMBAT_TORQUE[];
|
||||
extern const u8 Move_MAGICAL_TORQUE[];
|
||||
extern const u8 Move_PSYBLADE[];
|
||||
extern const u8 Move_HYDRO_STEAM[];
|
||||
extern const u8 Move_BLOOD_MOON[];
|
||||
extern const u8 Move_MATCHA_GOTCHA[];
|
||||
extern const u8 Move_SYRUP_BOMB[];
|
||||
extern const u8 Move_IVY_CUDGEL[];
|
||||
extern const u8 Move_ELECTRO_SHOT[];
|
||||
extern const u8 Move_TERA_STARSTORM[];
|
||||
extern const u8 Move_FICKLE_BEAM[];
|
||||
extern const u8 Move_BURNING_BULWARK[];
|
||||
extern const u8 Move_THUNDERCLAP[];
|
||||
extern const u8 Move_MIGHTY_CLEAVE[];
|
||||
extern const u8 Move_TACHYON_CUTTER[];
|
||||
extern const u8 Move_HARD_PRESS[];
|
||||
extern const u8 Move_DRAGON_CHEER[];
|
||||
extern const u8 Move_ALLURING_VOICE[];
|
||||
extern const u8 Move_TEMPER_FLARE[];
|
||||
extern const u8 Move_SUPERCELL_SLAM[];
|
||||
extern const u8 Move_PSYCHIC_NOISE[];
|
||||
extern const u8 Move_UPPER_HAND[];
|
||||
extern const u8 Move_MALIGNANT_CHAIN[];
|
||||
extern const u8 Move_BREAKNECK_BLITZ[];
|
||||
extern const u8 Move_ALL_OUT_PUMMELING[];
|
||||
extern const u8 Move_SUPERSONIC_SKYSTRIKE[];
|
||||
extern const u8 Move_ACID_DOWNPOUR[];
|
||||
extern const u8 Move_TECTONIC_RAGE[];
|
||||
extern const u8 Move_CONTINENTAL_CRUSH[];
|
||||
extern const u8 Move_SAVAGE_SPIN_OUT[];
|
||||
extern const u8 Move_NEVER_ENDING_NIGHTMARE[];
|
||||
extern const u8 Move_CORKSCREW_CRASH[];
|
||||
extern const u8 Move_INFERNO_OVERDRIVE[];
|
||||
extern const u8 Move_HYDRO_VORTEX[];
|
||||
extern const u8 Move_BLOOM_DOOM[];
|
||||
extern const u8 Move_GIGAVOLT_HAVOC[];
|
||||
extern const u8 Move_SHATTERED_PSYCHE[];
|
||||
extern const u8 Move_SUBZERO_SLAMMER[];
|
||||
extern const u8 Move_DEVASTATING_DRAKE[];
|
||||
extern const u8 Move_BLACK_HOLE_ECLIPSE[];
|
||||
extern const u8 Move_TWINKLE_TACKLE[];
|
||||
extern const u8 Move_CATASTROPIKA[];
|
||||
extern const u8 Move_10000000_VOLT_THUNDERBOLT[];
|
||||
extern const u8 Move_STOKED_SPARKSURFER[];
|
||||
extern const u8 Move_EXTREME_EVOBOOST[];
|
||||
extern const u8 Move_PULVERIZING_PANCAKE[];
|
||||
extern const u8 Move_GENESIS_SUPERNOVA[];
|
||||
extern const u8 Move_SINISTER_ARROW_RAID[];
|
||||
extern const u8 Move_MALICIOUS_MOONSAULT[];
|
||||
extern const u8 Move_OCEANIC_OPERETTA[];
|
||||
extern const u8 Move_SPLINTERED_STORMSHARDS[];
|
||||
extern const u8 Move_LETS_SNUGGLE_FOREVER[];
|
||||
extern const u8 Move_CLANGOROUS_SOULBLAZE[];
|
||||
extern const u8 Move_GUARDIAN_OF_ALOLA[];
|
||||
extern const u8 Move_SEARING_SUNRAZE_SMASH[];
|
||||
extern const u8 Move_MENACING_MOONRAZE_MAELSTROM[];
|
||||
extern const u8 Move_LIGHT_THAT_BURNS_THE_SKY[];
|
||||
extern const u8 Move_SOUL_STEALING_7_STAR_STRIKE[];
|
||||
extern const u8 Move_MAX_GUARD[];
|
||||
extern const u8 Move_MAX_FLARE[];
|
||||
extern const u8 Move_MAX_FLUTTERBY[];
|
||||
extern const u8 Move_MAX_LIGHTNING[];
|
||||
extern const u8 Move_MAX_STRIKE[];
|
||||
extern const u8 Move_MAX_KNUCKLE[];
|
||||
extern const u8 Move_MAX_PHANTASM[];
|
||||
extern const u8 Move_MAX_HAILSTORM[];
|
||||
extern const u8 Move_MAX_OOZE[];
|
||||
extern const u8 Move_MAX_GEYSER[];
|
||||
extern const u8 Move_MAX_AIRSTREAM[];
|
||||
extern const u8 Move_MAX_STARFALL[];
|
||||
extern const u8 Move_MAX_WYRMWIND[];
|
||||
extern const u8 Move_MAX_MINDSTORM[];
|
||||
extern const u8 Move_MAX_ROCKFALL[];
|
||||
extern const u8 Move_MAX_QUAKE[];
|
||||
extern const u8 Move_MAX_DARKNESS[];
|
||||
extern const u8 Move_MAX_OVERGROWTH[];
|
||||
extern const u8 Move_MAX_STEELSPIKE[];
|
||||
extern const u8 Move_G_MAX_VINE_LASH[];
|
||||
extern const u8 Move_G_MAX_WILDFIRE[];
|
||||
extern const u8 Move_G_MAX_CANNONADE[];
|
||||
extern const u8 Move_G_MAX_BEFUDDLE[];
|
||||
extern const u8 Move_G_MAX_VOLT_CRASH[];
|
||||
extern const u8 Move_G_MAX_GOLD_RUSH[];
|
||||
extern const u8 Move_G_MAX_CHI_STRIKE[];
|
||||
extern const u8 Move_G_MAX_TERROR[];
|
||||
extern const u8 Move_G_MAX_FOAM_BURST[];
|
||||
extern const u8 Move_G_MAX_RESONANCE[];
|
||||
extern const u8 Move_G_MAX_CUDDLE[];
|
||||
extern const u8 Move_G_MAX_REPLENISH[];
|
||||
extern const u8 Move_G_MAX_MALODOR[];
|
||||
extern const u8 Move_G_MAX_MELTDOWN[];
|
||||
extern const u8 Move_G_MAX_DRUM_SOLO[];
|
||||
extern const u8 Move_G_MAX_FIREBALL[];
|
||||
extern const u8 Move_G_MAX_HYDROSNIPE[];
|
||||
extern const u8 Move_G_MAX_WIND_RAGE[];
|
||||
extern const u8 Move_G_MAX_GRAVITAS[];
|
||||
extern const u8 Move_G_MAX_STONESURGE[];
|
||||
extern const u8 Move_G_MAX_VOLCALITH[];
|
||||
extern const u8 Move_G_MAX_TARTNESS[];
|
||||
extern const u8 Move_G_MAX_SWEETNESS[];
|
||||
extern const u8 Move_G_MAX_SANDBLAST[];
|
||||
extern const u8 Move_G_MAX_STUN_SHOCK[];
|
||||
extern const u8 Move_G_MAX_CENTIFERNO[];
|
||||
extern const u8 Move_G_MAX_SMITE[];
|
||||
extern const u8 Move_G_MAX_SNOOZE[];
|
||||
extern const u8 Move_G_MAX_FINALE[];
|
||||
extern const u8 Move_G_MAX_STEELSURGE[];
|
||||
extern const u8 Move_G_MAX_DEPLETION[];
|
||||
extern const u8 Move_G_MAX_ONE_BLOW[];
|
||||
extern const u8 Move_G_MAX_RAPID_FLOW[];
|
||||
|
||||
#endif // GUARD_BATTLE_ANIM_SCRIPTS_H
|
||||
@ -144,5 +144,6 @@ void TryAddLastUsedBallItemSprites(void);
|
||||
void SwapBallToDisplay(bool32 sameBall);
|
||||
void ArrowsChangeColorLastBallCycle(bool32 showArrows);
|
||||
void UpdateAbilityPopup(u8 battlerId);
|
||||
void CategoryIcons_LoadSpritesGfx(void);
|
||||
|
||||
#endif // GUARD_BATTLE_INTERFACE_H
|
||||
|
||||
@ -78,6 +78,7 @@ extern const struct SpriteTemplate gUnusedBattleInitSprite;
|
||||
extern const struct OamData gOamData_BattleSpriteOpponentSide;
|
||||
extern const struct OamData gOamData_BattleSpritePlayerSide;
|
||||
extern const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES];
|
||||
extern const uq4_12_t gTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES];
|
||||
|
||||
extern const u8 gStatusConditionString_PoisonJpn[8];
|
||||
extern const u8 gStatusConditionString_SleepJpn[8];
|
||||
|
||||
@ -66,6 +66,10 @@ enum {
|
||||
#define IS_WHOLE_SIDE_ALIVE(battler) ((IsBattlerAlive(battler) && IsBattlerAlive(BATTLE_PARTNER(battler))))
|
||||
#define IS_ALIVE_AND_PRESENT(battler) (IsBattlerAlive(battler) && IsBattlerSpritePresent(battler))
|
||||
|
||||
// Lowest and highest percentages used for damage roll calculations
|
||||
#define DMG_ROLL_PERCENT_LO 85
|
||||
#define DMG_ROLL_PERCENT_HI 100
|
||||
|
||||
// for Natural Gift and Fling
|
||||
struct TypePower
|
||||
{
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
#define B_GHOSTS_ESCAPE GEN_LATEST // In Gen6+, abilities like Shadow Tag or moves like Mean Look fail on Ghost-type Pokémon. They can also escape any Wild Battle.
|
||||
#define B_PARALYZE_ELECTRIC GEN_LATEST // In Gen6+, Electric-type Pokémon can't be paralyzed.
|
||||
#define B_POWDER_GRASS GEN_LATEST // In Gen6+, Grass-type Pokémon are immune to powder and spore moves.
|
||||
#define B_UPDATED_TYPE_MATCHUPS GEN_LATEST // Updates Type matchups. Refer to sTypeEffectivenessTable for details.
|
||||
#define B_UPDATED_TYPE_MATCHUPS GEN_LATEST // Updates Type matchups. src/data/types_info.h for details.
|
||||
#define B_PRANKSTER_DARK_TYPES GEN_LATEST // In Gen7+, Prankster-elevated status moves do not affect Dark type Pokémon.
|
||||
#define B_SHEER_COLD_IMMUNITY GEN_LATEST // In Gen7+, Ice-types are immune to Sheer Cold
|
||||
#define B_ROOST_PURE_FLYING GEN_LATEST // In Gen5+, Roost makes pure Flying-types into Normal-type.
|
||||
|
||||
@ -477,6 +477,7 @@
|
||||
#define B_WIN_VS_OUTCOME_DRAW 21
|
||||
#define B_WIN_VS_OUTCOME_LEFT 22
|
||||
#define B_WIN_VS_OUTCOME_RIGHT 23
|
||||
#define B_WIN_MOVE_DESCRIPTION 24
|
||||
|
||||
// The following are duplicate id values for windows that Battle Arena uses differently.
|
||||
#define ARENA_WIN_PLAYER_NAME 15
|
||||
|
||||
@ -118,125 +118,123 @@
|
||||
#define VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC 26
|
||||
#define VARIOUS_STAT_TEXT_BUFFER 27
|
||||
#define VARIOUS_SWITCHIN_ABILITIES 28
|
||||
#define VARIOUS_SAVE_TARGET 29
|
||||
#define VARIOUS_RESTORE_TARGET 30
|
||||
#define VARIOUS_INSTANT_HP_DROP 31
|
||||
#define VARIOUS_CLEAR_STATUS 32
|
||||
#define VARIOUS_RESTORE_PP 33
|
||||
#define VARIOUS_TRY_ACTIVATE_MOXIE 34
|
||||
#define VARIOUS_TRY_ACTIVATE_FELL_STINGER 35
|
||||
#define VARIOUS_PLAY_MOVE_ANIMATION 36
|
||||
#define VARIOUS_SET_LUCKY_CHANT 37
|
||||
#define VARIOUS_SUCKER_PUNCH_CHECK 38
|
||||
#define VARIOUS_SET_SIMPLE_BEAM 39
|
||||
#define VARIOUS_TRY_ENTRAINMENT 40
|
||||
#define VARIOUS_SET_LAST_USED_ABILITY 41
|
||||
#define VARIOUS_INVERT_STAT_STAGES 42
|
||||
#define VARIOUS_TRY_ME_FIRST 43
|
||||
#define VARIOUS_JUMP_IF_BATTLE_END 44
|
||||
#define VARIOUS_TRY_ELECTRIFY 45
|
||||
#define VARIOUS_TRY_REFLECT_TYPE 46
|
||||
#define VARIOUS_TRY_SOAK 47
|
||||
#define VARIOUS_HANDLE_MEGA_EVO 48
|
||||
#define VARIOUS_TRY_LAST_RESORT 49
|
||||
#define VARIOUS_SET_ARG_TO_BATTLE_DAMAGE 50
|
||||
#define VARIOUS_TRY_HIT_SWITCH_TARGET 51
|
||||
#define VARIOUS_TRY_AUTOTOMIZE 52
|
||||
#define VARIOUS_ABILITY_POPUP 53
|
||||
#define VARIOUS_JUMP_IF_TARGET_ALLY 54
|
||||
#define VARIOUS_TRY_SYNCHRONOISE 55
|
||||
#define VARIOUS_PSYCHO_SHIFT 56
|
||||
#define VARIOUS_CURE_STATUS 57
|
||||
#define VARIOUS_POWER_TRICK 58
|
||||
#define VARIOUS_AFTER_YOU 59
|
||||
#define VARIOUS_BESTOW 60
|
||||
#define VARIOUS_JUMP_IF_NOT_GROUNDED 61
|
||||
#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 62
|
||||
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 63
|
||||
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 64
|
||||
#define VARIOUS_SET_AURORA_VEIL 65
|
||||
#define VARIOUS_TRY_THIRD_TYPE 66
|
||||
#define VARIOUS_ACUPRESSURE 67
|
||||
#define VARIOUS_SET_POWDER 68
|
||||
#define VARIOUS_SPECTRAL_THIEF 69
|
||||
#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 70
|
||||
#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 71
|
||||
#define VARIOUS_JUMP_IF_ROAR_FAILS 72
|
||||
#define VARIOUS_TRY_INSTRUCT 73
|
||||
#define VARIOUS_JUMP_IF_NOT_BERRY 74
|
||||
#define VARIOUS_TRACE_ABILITY 75
|
||||
#define VARIOUS_UPDATE_NICK 76
|
||||
#define VARIOUS_TRY_ILLUSION_OFF 77
|
||||
#define VARIOUS_SET_SPRITEIGNORE0HP 78
|
||||
#define VARIOUS_HANDLE_FORM_CHANGE 79
|
||||
#define VARIOUS_GET_STAT_VALUE 80
|
||||
#define VARIOUS_JUMP_IF_FULL_HP 81
|
||||
#define VARIOUS_LOSE_TYPE 82
|
||||
#define VARIOUS_TRY_ACTIVATE_SOULHEART 83
|
||||
#define VARIOUS_TRY_ACTIVATE_RECEIVER 84
|
||||
#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 85
|
||||
#define VARIOUS_TRY_FRISK 86
|
||||
#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 87
|
||||
#define VARIOUS_TRY_FAIRY_LOCK 88
|
||||
#define VARIOUS_JUMP_IF_NO_ALLY 89
|
||||
#define VARIOUS_POISON_TYPE_IMMUNITY 90
|
||||
#define VARIOUS_JUMP_IF_HOLD_EFFECT 91
|
||||
#define VARIOUS_INFATUATE_WITH_BATTLER 92
|
||||
#define VARIOUS_SET_LAST_USED_ITEM 93
|
||||
#define VARIOUS_PARALYZE_TYPE_IMMUNITY 94
|
||||
#define VARIOUS_JUMP_IF_ABSENT 95
|
||||
#define VARIOUS_DESTROY_ABILITY_POPUP 96
|
||||
#define VARIOUS_TOTEM_BOOST 97
|
||||
#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 98
|
||||
#define VARIOUS_MOVEEND_ITEM_EFFECTS 99
|
||||
#define VARIOUS_TERRAIN_SEED 100
|
||||
#define VARIOUS_MAKE_INVISIBLE 101
|
||||
#define VARIOUS_ROOM_SERVICE 102
|
||||
#define VARIOUS_EERIE_SPELL_PP_REDUCE 103
|
||||
#define VARIOUS_JUMP_IF_TEAM_HEALTHY 104
|
||||
#define VARIOUS_TRY_HEAL_QUARTER_HP 105
|
||||
#define VARIOUS_REMOVE_TERRAIN 106
|
||||
#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 107
|
||||
#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 108
|
||||
#define VARIOUS_GET_ROTOTILLER_TARGETS 109
|
||||
#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 110
|
||||
#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 111
|
||||
#define VARIOUS_CONSUME_BERRY 112
|
||||
#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 113
|
||||
#define VARIOUS_JUMP_IF_SPECIES 114
|
||||
#define VARIOUS_UPDATE_ABILITY_POPUP 115
|
||||
#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 116
|
||||
#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 117
|
||||
#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 118
|
||||
#define VARIOUS_SHELL_SIDE_ARM_CHECK 119
|
||||
#define VARIOUS_TRY_NO_RETREAT 120
|
||||
#define VARIOUS_TRY_TAR_SHOT 121
|
||||
#define VARIOUS_CAN_TAR_SHOT_WORK 122
|
||||
#define VARIOUS_CHECK_POLTERGEIST 123
|
||||
#define VARIOUS_CUT_1_3_HP_RAISE_STATS 124
|
||||
#define VARIOUS_TRY_END_NEUTRALIZING_GAS 125
|
||||
#define VARIOUS_JUMP_IF_UNDER_200 126
|
||||
#define VARIOUS_SET_SKY_DROP 127
|
||||
#define VARIOUS_CLEAR_SKY_DROP 128
|
||||
#define VARIOUS_SKY_DROP_YAWN 129
|
||||
#define VARIOUS_CURE_CERTAIN_STATUSES 130
|
||||
#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 131
|
||||
#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 132
|
||||
#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 133
|
||||
#define VARIOUS_SAVE_BATTLER_ITEM 134
|
||||
#define VARIOUS_RESTORE_BATTLER_ITEM 135
|
||||
#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 136
|
||||
#define VARIOUS_SET_BEAK_BLAST 137
|
||||
#define VARIOUS_SWAP_SIDE_STATUSES 138
|
||||
#define VARIOUS_SWAP_STATS 139
|
||||
#define VARIOUS_TEATIME_INVUL 140
|
||||
#define VARIOUS_TEATIME_TARGETS 141
|
||||
#define VARIOUS_TRY_WIND_RIDER_POWER 142
|
||||
#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 143
|
||||
#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 144
|
||||
#define VARIOUS_STORE_HEALING_WISH 145
|
||||
#define VARIOUS_HIT_SWITCH_TARGET_FAILED 146
|
||||
#define VARIOUS_TRY_REVIVAL_BLESSING 147
|
||||
#define VARIOUS_INSTANT_HP_DROP 29
|
||||
#define VARIOUS_CLEAR_STATUS 30
|
||||
#define VARIOUS_RESTORE_PP 31
|
||||
#define VARIOUS_TRY_ACTIVATE_MOXIE 32
|
||||
#define VARIOUS_TRY_ACTIVATE_FELL_STINGER 33
|
||||
#define VARIOUS_PLAY_MOVE_ANIMATION 34
|
||||
#define VARIOUS_SET_LUCKY_CHANT 35
|
||||
#define VARIOUS_SUCKER_PUNCH_CHECK 36
|
||||
#define VARIOUS_SET_SIMPLE_BEAM 37
|
||||
#define VARIOUS_TRY_ENTRAINMENT 38
|
||||
#define VARIOUS_SET_LAST_USED_ABILITY 39
|
||||
#define VARIOUS_INVERT_STAT_STAGES 40
|
||||
#define VARIOUS_TRY_ME_FIRST 41
|
||||
#define VARIOUS_JUMP_IF_BATTLE_END 42
|
||||
#define VARIOUS_TRY_ELECTRIFY 43
|
||||
#define VARIOUS_TRY_REFLECT_TYPE 44
|
||||
#define VARIOUS_TRY_SOAK 45
|
||||
#define VARIOUS_HANDLE_MEGA_EVO 46
|
||||
#define VARIOUS_TRY_LAST_RESORT 47
|
||||
#define VARIOUS_SET_ARG_TO_BATTLE_DAMAGE 48
|
||||
#define VARIOUS_TRY_HIT_SWITCH_TARGET 49
|
||||
#define VARIOUS_TRY_AUTOTOMIZE 50
|
||||
#define VARIOUS_ABILITY_POPUP 51
|
||||
#define VARIOUS_JUMP_IF_TARGET_ALLY 52
|
||||
#define VARIOUS_TRY_SYNCHRONOISE 53
|
||||
#define VARIOUS_PSYCHO_SHIFT 54
|
||||
#define VARIOUS_CURE_STATUS 55
|
||||
#define VARIOUS_POWER_TRICK 56
|
||||
#define VARIOUS_AFTER_YOU 57
|
||||
#define VARIOUS_BESTOW 58
|
||||
#define VARIOUS_JUMP_IF_NOT_GROUNDED 59
|
||||
#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 60
|
||||
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 61
|
||||
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 62
|
||||
#define VARIOUS_SET_AURORA_VEIL 63
|
||||
#define VARIOUS_TRY_THIRD_TYPE 64
|
||||
#define VARIOUS_ACUPRESSURE 65
|
||||
#define VARIOUS_SET_POWDER 66
|
||||
#define VARIOUS_SPECTRAL_THIEF 67
|
||||
#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 68
|
||||
#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 69
|
||||
#define VARIOUS_JUMP_IF_ROAR_FAILS 70
|
||||
#define VARIOUS_TRY_INSTRUCT 71
|
||||
#define VARIOUS_JUMP_IF_NOT_BERRY 72
|
||||
#define VARIOUS_TRACE_ABILITY 73
|
||||
#define VARIOUS_UPDATE_NICK 74
|
||||
#define VARIOUS_TRY_ILLUSION_OFF 75
|
||||
#define VARIOUS_SET_SPRITEIGNORE0HP 76
|
||||
#define VARIOUS_HANDLE_FORM_CHANGE 77
|
||||
#define VARIOUS_GET_STAT_VALUE 78
|
||||
#define VARIOUS_JUMP_IF_FULL_HP 79
|
||||
#define VARIOUS_LOSE_TYPE 80
|
||||
#define VARIOUS_TRY_ACTIVATE_SOULHEART 81
|
||||
#define VARIOUS_TRY_ACTIVATE_RECEIVER 82
|
||||
#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 83
|
||||
#define VARIOUS_TRY_FRISK 84
|
||||
#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 85
|
||||
#define VARIOUS_TRY_FAIRY_LOCK 86
|
||||
#define VARIOUS_JUMP_IF_NO_ALLY 87
|
||||
#define VARIOUS_POISON_TYPE_IMMUNITY 88
|
||||
#define VARIOUS_JUMP_IF_HOLD_EFFECT 89
|
||||
#define VARIOUS_INFATUATE_WITH_BATTLER 90
|
||||
#define VARIOUS_SET_LAST_USED_ITEM 91
|
||||
#define VARIOUS_PARALYZE_TYPE_IMMUNITY 92
|
||||
#define VARIOUS_JUMP_IF_ABSENT 93
|
||||
#define VARIOUS_DESTROY_ABILITY_POPUP 94
|
||||
#define VARIOUS_TOTEM_BOOST 95
|
||||
#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 96
|
||||
#define VARIOUS_MOVEEND_ITEM_EFFECTS 97
|
||||
#define VARIOUS_TERRAIN_SEED 98
|
||||
#define VARIOUS_MAKE_INVISIBLE 99
|
||||
#define VARIOUS_ROOM_SERVICE 100
|
||||
#define VARIOUS_EERIE_SPELL_PP_REDUCE 101
|
||||
#define VARIOUS_JUMP_IF_TEAM_HEALTHY 102
|
||||
#define VARIOUS_TRY_HEAL_QUARTER_HP 103
|
||||
#define VARIOUS_REMOVE_TERRAIN 104
|
||||
#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 105
|
||||
#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 106
|
||||
#define VARIOUS_GET_ROTOTILLER_TARGETS 107
|
||||
#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 108
|
||||
#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 109
|
||||
#define VARIOUS_CONSUME_BERRY 110
|
||||
#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 111
|
||||
#define VARIOUS_JUMP_IF_SPECIES 112
|
||||
#define VARIOUS_UPDATE_ABILITY_POPUP 113
|
||||
#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 114
|
||||
#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 115
|
||||
#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 116
|
||||
#define VARIOUS_SHELL_SIDE_ARM_CHECK 117
|
||||
#define VARIOUS_TRY_NO_RETREAT 118
|
||||
#define VARIOUS_TRY_TAR_SHOT 119
|
||||
#define VARIOUS_CAN_TAR_SHOT_WORK 120
|
||||
#define VARIOUS_CHECK_POLTERGEIST 121
|
||||
#define VARIOUS_CUT_1_3_HP_RAISE_STATS 122
|
||||
#define VARIOUS_TRY_END_NEUTRALIZING_GAS 123
|
||||
#define VARIOUS_JUMP_IF_UNDER_200 124
|
||||
#define VARIOUS_SET_SKY_DROP 125
|
||||
#define VARIOUS_CLEAR_SKY_DROP 126
|
||||
#define VARIOUS_SKY_DROP_YAWN 127
|
||||
#define VARIOUS_CURE_CERTAIN_STATUSES 128
|
||||
#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 129
|
||||
#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 130
|
||||
#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 131
|
||||
#define VARIOUS_SAVE_BATTLER_ITEM 132
|
||||
#define VARIOUS_RESTORE_BATTLER_ITEM 133
|
||||
#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 134
|
||||
#define VARIOUS_SET_BEAK_BLAST 135
|
||||
#define VARIOUS_SWAP_SIDE_STATUSES 136
|
||||
#define VARIOUS_SWAP_STATS 137
|
||||
#define VARIOUS_TEATIME_INVUL 138
|
||||
#define VARIOUS_TEATIME_TARGETS 139
|
||||
#define VARIOUS_TRY_WIND_RIDER_POWER 140
|
||||
#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 141
|
||||
#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 142
|
||||
#define VARIOUS_STORE_HEALING_WISH 143
|
||||
#define VARIOUS_HIT_SWITCH_TARGET_FAILED 144
|
||||
#define VARIOUS_TRY_REVIVAL_BLESSING 145
|
||||
|
||||
// Cmd_manipulatedamage
|
||||
#define DMG_CHANGE_SIGN 0
|
||||
|
||||
@ -2,28 +2,28 @@
|
||||
#define GUARD_CONSTANTS_POKEMON_H
|
||||
|
||||
// Pokémon types
|
||||
#define TYPE_NONE 255
|
||||
#define TYPE_NORMAL 0
|
||||
#define TYPE_FIGHTING 1
|
||||
#define TYPE_FLYING 2
|
||||
#define TYPE_POISON 3
|
||||
#define TYPE_GROUND 4
|
||||
#define TYPE_ROCK 5
|
||||
#define TYPE_BUG 6
|
||||
#define TYPE_GHOST 7
|
||||
#define TYPE_STEEL 8
|
||||
#define TYPE_MYSTERY 9
|
||||
#define TYPE_FIRE 10
|
||||
#define TYPE_WATER 11
|
||||
#define TYPE_GRASS 12
|
||||
#define TYPE_ELECTRIC 13
|
||||
#define TYPE_PSYCHIC 14
|
||||
#define TYPE_ICE 15
|
||||
#define TYPE_DRAGON 16
|
||||
#define TYPE_DARK 17
|
||||
#define TYPE_FAIRY 18
|
||||
#define TYPE_STELLAR 19
|
||||
#define NUMBER_OF_MON_TYPES 20
|
||||
#define TYPE_NONE 0
|
||||
#define TYPE_NORMAL 1
|
||||
#define TYPE_FIGHTING 2
|
||||
#define TYPE_FLYING 3
|
||||
#define TYPE_POISON 4
|
||||
#define TYPE_GROUND 5
|
||||
#define TYPE_ROCK 6
|
||||
#define TYPE_BUG 7
|
||||
#define TYPE_GHOST 8
|
||||
#define TYPE_STEEL 9
|
||||
#define TYPE_MYSTERY 10
|
||||
#define TYPE_FIRE 11
|
||||
#define TYPE_WATER 12
|
||||
#define TYPE_GRASS 13
|
||||
#define TYPE_ELECTRIC 14
|
||||
#define TYPE_PSYCHIC 15
|
||||
#define TYPE_ICE 16
|
||||
#define TYPE_DRAGON 17
|
||||
#define TYPE_DARK 18
|
||||
#define TYPE_FAIRY 19
|
||||
#define TYPE_STELLAR 20
|
||||
#define NUMBER_OF_MON_TYPES 21
|
||||
|
||||
// Pokémon egg groups
|
||||
#define EGG_GROUP_NONE 0
|
||||
|
||||
@ -109,6 +109,9 @@ struct TypeInfo
|
||||
u8 palette;
|
||||
u16 zMove;
|
||||
u16 maxMove;
|
||||
u16 teraTypeRGBValue; // Most values pulled from the Tera type icon palette.
|
||||
u16 damageCategory:2; // Used for B_PHYSICAL_SPECIAL_SPLIT <= GEN_3
|
||||
u16 padding:14;
|
||||
const u32 *const paletteTMHM;
|
||||
//u16 enhanceItem;
|
||||
//u16 berry;
|
||||
|
||||
@ -1983,6 +1983,8 @@ extern const u32 gSummaryMoveSelect_Gfx[];
|
||||
extern const u32 gSummaryMoveSelect_Pal[];
|
||||
extern const u32 gStatusGfx_Icons[];
|
||||
extern const u32 gStatusPal_Icons[];
|
||||
extern const u16 gCategoryIcons_Pal[];
|
||||
extern const u32 gCategoryIcons_Gfx[];
|
||||
|
||||
extern const u32 gShopMenu_Gfx[];
|
||||
extern const u32 gShopMenu_Tilemap[];
|
||||
|
||||
@ -524,6 +524,7 @@ struct MoveInfo
|
||||
u32 parentalBondBanned:1;
|
||||
u32 skyBattleBanned:1;
|
||||
u32 sketchBanned:1;
|
||||
u32 padding:5; // end of word
|
||||
|
||||
u32 argument;
|
||||
|
||||
@ -535,6 +536,7 @@ struct MoveInfo
|
||||
u8 contestCategory:3;
|
||||
u8 contestComboStarterId;
|
||||
u8 contestComboMoves[MAX_COMBO_MOVES];
|
||||
const u8 *battleAnimScript;
|
||||
};
|
||||
|
||||
#define EFFECTS_ARR(...) (const struct AdditionalEffect[]) {__VA_ARGS__}
|
||||
@ -873,5 +875,6 @@ u16 GetSpeciesPreEvolution(u16 species);
|
||||
void HealPokemon(struct Pokemon *mon);
|
||||
void HealBoxPokemon(struct BoxPokemon *boxMon);
|
||||
const u8 *GetMoveName(u16 moveId);
|
||||
const u8 *GetMoveAnimationScript(u16 moveId);
|
||||
|
||||
#endif // GUARD_POKEMON_H
|
||||
|
||||
@ -5,10 +5,12 @@
|
||||
|
||||
extern u8 gLastViewedMonIndex;
|
||||
|
||||
extern const u8 *const gMoveDescriptionPointers[];
|
||||
extern const u8 gNotDoneYetDescription[];
|
||||
extern const struct SpriteTemplate gSpriteTemplate_MoveTypes;
|
||||
extern const struct CompressedSpriteSheet gSpriteSheet_MoveTypes;
|
||||
extern const struct CompressedSpriteSheet gSpriteSheet_CategoryIcons;
|
||||
extern const struct SpritePalette gSpritePal_CategoryIcons;
|
||||
extern const struct SpriteTemplate gSpriteTemplate_CategoryIcons;
|
||||
|
||||
void ShowPokemonSummaryScreen(u8 mode, void *mons, u8 monIndex, u8 maxMonIndex, void (*callback)(void));
|
||||
void ShowSelectMovePokemonSummaryScreen(struct Pokemon *mons, u8 monIndex, u8 maxMonIndex, void (*callback)(void), u16 newMove);
|
||||
|
||||
@ -824,6 +824,12 @@ struct moveWithPP {
|
||||
#define SpAttack(spAttack) SpAttack_(__LINE__, spAttack)
|
||||
#define SpDefense(spDefense) SpDefense_(__LINE__, spDefense)
|
||||
#define Speed(speed) Speed_(__LINE__, speed)
|
||||
#define HPIV(hpIV) HPIV_(__LINE__, hpIV)
|
||||
#define AttackIV(attackIV) AttackIV_(__LINE__, attackIV)
|
||||
#define DefenseIV(defenseIV) DefenseIV_(__LINE__, defenseIV)
|
||||
#define SpAttackIV(spAttackIV) SpAttackIV_(__LINE__, spAttackIV)
|
||||
#define SpDefenseIV(spDefenseIV) SpDefenseIV_(__LINE__, spDefenseIV)
|
||||
#define SpeedIV(speedIV) SpeedIV_(__LINE__, speedIV)
|
||||
#define Item(item) Item_(__LINE__, item)
|
||||
#define Moves(move1, ...) do { u16 moves_[MAX_MON_MOVES] = {move1, __VA_ARGS__}; Moves_(__LINE__, moves_); } while(0)
|
||||
#define MovesWithPP(movewithpp1, ...) MovesWithPP_(__LINE__, (struct moveWithPP[MAX_MON_MOVES]) {movewithpp1, __VA_ARGS__})
|
||||
@ -854,6 +860,12 @@ void Defense_(u32 sourceLine, u32 defense);
|
||||
void SpAttack_(u32 sourceLine, u32 spAttack);
|
||||
void SpDefense_(u32 sourceLine, u32 spDefense);
|
||||
void Speed_(u32 sourceLine, u32 speed);
|
||||
void HPIV_(u32 sourceLine, u32 hpIV);
|
||||
void AttackIV_(u32 sourceLine, u32 attackIV);
|
||||
void DefenseIV_(u32 sourceLine, u32 defenseIV);
|
||||
void SpAttackIV_(u32 sourceLine, u32 spAttackIV);
|
||||
void SpDefenseIV_(u32 sourceLine, u32 spDefenseIV);
|
||||
void SpeedIV_(u32 sourceLine, u32 speedIV);
|
||||
void Item_(u32 sourceLine, u32 item);
|
||||
void Moves_(u32 sourceLine, u16 moves[MAX_MON_MOVES]);
|
||||
void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]);
|
||||
|
||||
@ -75,7 +75,7 @@ void Test_ExpectedResult(enum TestResult);
|
||||
void Test_ExpectLeaks(bool32);
|
||||
void Test_ExitWithResult(enum TestResult, const char *fmt, ...);
|
||||
|
||||
s32 MgbaPrintf_(const char *fmt, ...);
|
||||
s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
|
||||
#define TEST(_name) \
|
||||
static void CAT(Test, __LINE__)(void); \
|
||||
@ -193,7 +193,7 @@ static inline struct Benchmark BenchmarkStop(void)
|
||||
do \
|
||||
{ \
|
||||
u32 a_ = (a).ticks; u32 b_ = (b).ticks; \
|
||||
MgbaPrintf_(#a ": %d ticks, " #b ": %d ticks", a_, b_); \
|
||||
Test_MgbaPrintf(#a ": %d ticks, " #b ": %d ticks", a_, b_); \
|
||||
if (((a_ - BENCHMARK_ABS) * BENCHMARK_REL) >= (b_ * 100)) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_FASTER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
} while (0)
|
||||
@ -202,7 +202,7 @@ static inline struct Benchmark BenchmarkStop(void)
|
||||
do \
|
||||
{ \
|
||||
u32 a_ = (a).ticks; u32 b_ = (b).ticks; \
|
||||
MgbaPrintf_(#a ": %d ticks, " #b ": %d ticks", a_, b_); \
|
||||
Test_MgbaPrintf(#a ": %d ticks, " #b ": %d ticks", a_, b_); \
|
||||
if ((a_ * 100) <= ((b_ - BENCHMARK_ABS) * BENCHMARK_REL)) \
|
||||
Test_ExitWithResult(TEST_RESULT_FAIL, "%s:%d: EXPECT_SLOWER(" #a ", " #b ") failed", gTestRunnerState.test->filename, __LINE__); \
|
||||
} while (0)
|
||||
@ -215,7 +215,7 @@ static inline struct Benchmark BenchmarkStop(void)
|
||||
|
||||
#define PARAMETRIZE if (gFunctionTestRunnerState->parameters++ == gFunctionTestRunnerState->runParameter)
|
||||
|
||||
#define PARAMETRIZE_LABEL(f, label) if (gFunctionTestRunnerState->parameters++ == gFunctionTestRunnerState->runParameter && (MgbaPrintf_(":N%s: " f " (%d/%d)", gTestRunnerState.test->name, label, gFunctionTestRunnerState->runParameter + 1, gFunctionTestRunnerState->parameters), 1))
|
||||
#define PARAMETRIZE_LABEL(f, label) if (gFunctionTestRunnerState->parameters++ == gFunctionTestRunnerState->runParameter && (Test_MgbaPrintf(":N%s: " f " (%d/%d)", gTestRunnerState.test->name, label, gFunctionTestRunnerState->runParameter + 1, gFunctionTestRunnerState->parameters), 1))
|
||||
|
||||
#define TO_DO \
|
||||
do { \
|
||||
|
||||
63
migration_scripts/battle_anim_moves_refactor.py
Normal file
63
migration_scripts/battle_anim_moves_refactor.py
Normal file
@ -0,0 +1,63 @@
|
||||
import re
|
||||
|
||||
def IsCommaMissing(line: str):
|
||||
sanitized_line = line.removesuffix('\n').strip()
|
||||
if sanitized_line.endswith('{') or sanitized_line.endswith('(') or sanitized_line.endswith(','):
|
||||
return False
|
||||
if not re.search(r'\.[A-Za-z0-9_]+', sanitized_line):
|
||||
return False
|
||||
return True
|
||||
|
||||
input_file = open('./src/data/moves_info.h', 'r')
|
||||
lines = input_file.readlines()
|
||||
input_file.close()
|
||||
|
||||
|
||||
battle_anim_lines = []
|
||||
moves_info_lines = []
|
||||
|
||||
move = None
|
||||
bracketCount = 0
|
||||
for line in lines:
|
||||
m = re.search(r'\[MOVE_([A-Za-z0-9_]+)\] =', line)
|
||||
if m:
|
||||
move = m.group(1)
|
||||
bracketCount = 0
|
||||
battle_anim_lines.append('extern const u8 Move_' + move + '[];\n')
|
||||
|
||||
if move and re.search(r'\{', line):
|
||||
bracketCount = bracketCount + 1
|
||||
|
||||
if move and re.search(r'\}', line):
|
||||
if (bracketCount == 1):
|
||||
moves_info_lines.append(8 * ' ' + '.battleAnimScript = Move_' + move + ',\n')
|
||||
move = None
|
||||
bracketCount = bracketCount - 1
|
||||
|
||||
comment_split = line.split('//')
|
||||
if move and IsCommaMissing(comment_split[0]):
|
||||
line = comment_split[0].removesuffix('\n') + ',' + line[len(comment_split[0]):-1] + '\n'
|
||||
|
||||
|
||||
moves_info_lines.append(line)
|
||||
|
||||
output_file_mi = open('./src/data/moves_info.h', 'w')
|
||||
output_file_mi.writelines(moves_info_lines)
|
||||
output_file_mi.close()
|
||||
|
||||
output_file_bas = open('./include/battle_anim_scripts.h', 'w')
|
||||
output_file_bas.writelines('#ifndef GUARD_BATTLE_ANIM_SCRIPTS_H\n')
|
||||
output_file_bas.writelines('#define GUARD_BATTLE_ANIM_SCRIPTS_H\n\n')
|
||||
output_file_bas.writelines(battle_anim_lines)
|
||||
output_file_bas.writelines('\n#endif // GUARD_BATTLE_ANIM_SCRIPTS_H\n')
|
||||
output_file_bas.close()
|
||||
|
||||
b_anim_scripts_s = open('./data/battle_anim_scripts.s', 'r')
|
||||
lines = b_anim_scripts_s.read()
|
||||
b_anim_scripts_s.close()
|
||||
|
||||
lines = re.sub(r'(Move_[A-Za-z0-9_]*)([:]+)', r'\1::', lines)
|
||||
|
||||
b_anim_scripts_s = open('./data/battle_anim_scripts.s', 'w')
|
||||
b_anim_scripts_s.write(lines)
|
||||
b_anim_scripts_s.close()
|
||||
@ -464,7 +464,7 @@ static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u3
|
||||
else if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather, DMG_ROLL_LOWEST);
|
||||
else
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather, DMG_ROLL_AVERAGE);
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather, DMG_ROLL_DEFAULT);
|
||||
aiData->moveAccuracy[battlerAtk][battlerDef][i] = Ai_SetMoveAccuracy(aiData, battlerAtk, battlerDef, move);
|
||||
}
|
||||
aiData->simulatedDmg[battlerAtk][battlerDef][i] = dmg;
|
||||
@ -834,7 +834,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (gMovesInfo[move].powderMove && !IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))
|
||||
RETURN_SCORE_MINUS(10);
|
||||
|
||||
if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
|
||||
if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
RETURN_SCORE_MINUS(10);
|
||||
|
||||
if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
@ -1079,7 +1079,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
switch (moveEffect)
|
||||
{
|
||||
case EFFECT_HIT: // only applies to Vital Throw
|
||||
if (gMovesInfo[move].priority < 0 && AI_STRIKES_FIRST(battlerAtk, battlerDef, move) && aiData->hpPercents[battlerAtk] < 40)
|
||||
if (gMovesInfo[move].priority < 0 && AI_IsFaster(battlerAtk, battlerDef, move) && aiData->hpPercents[battlerAtk] < 40)
|
||||
ADJUST_SCORE(-2); // don't want to move last
|
||||
break;
|
||||
default:
|
||||
@ -1434,8 +1434,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_MIRROR_COAT:
|
||||
if (IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION))
|
||||
ADJUST_SCORE(-1);
|
||||
if (predictedMove == MOVE_NONE || GetBattleMoveCategory(predictedMove) == DAMAGE_CATEGORY_STATUS
|
||||
if ((predictedMove == MOVE_NONE || GetBattleMoveCategory(predictedMove) == DAMAGE_CATEGORY_STATUS
|
||||
|| DoesSubstituteBlockMove(battlerAtk, BATTLE_PARTNER(battlerDef), predictedMove))
|
||||
&& !(predictedMove == MOVE_NONE && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY))) // Let Risky AI predict blindly based on stats
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
|
||||
@ -1522,7 +1523,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
|
||||
&& !PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
{
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker should go first
|
||||
{
|
||||
if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF)
|
||||
ADJUST_SCORE(-10); // no anticipated move to disable
|
||||
@ -1544,7 +1545,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
|
||||
&& !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
{
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker should go first
|
||||
{
|
||||
if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF)
|
||||
ADJUST_SCORE(-10); // no anticipated move to encore
|
||||
@ -1911,7 +1912,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-8); //No point in healing, but should at least do it if nothing better
|
||||
break;
|
||||
case EFFECT_RECOIL_IF_MISS:
|
||||
if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && AI_DATA->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] < 75)
|
||||
if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && AI_DATA->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] < 75
|
||||
&& !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY))
|
||||
ADJUST_SCORE(-6);
|
||||
break;
|
||||
case EFFECT_TRANSFORM:
|
||||
@ -1921,7 +1923,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_SPITE:
|
||||
case EFFECT_MIMIC:
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker should go first
|
||||
{
|
||||
if (gLastMoves[battlerDef] == MOVE_NONE
|
||||
|| gLastMoves[battlerDef] == 0xFFFF)
|
||||
@ -2066,7 +2068,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (isDoubleBattle)
|
||||
{
|
||||
if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // partner is going to set up hazards
|
||||
&& AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerAtk, aiData->partnerMove) == AI_IS_FASTER) // partner is going to set up before the potential Defog
|
||||
&& AI_IsFaster(BATTLE_PARTNER(battlerAtk), battlerAtk, aiData->partnerMove)) // partner is going to set up before the potential Defog
|
||||
{
|
||||
ADJUST_SCORE(-10);
|
||||
break; // Don't use Defog if partner is going to set up hazards
|
||||
@ -2094,7 +2096,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_SEMI_INVULNERABLE:
|
||||
if (predictedMove != MOVE_NONE
|
||||
&& AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER
|
||||
&& AI_IsSlower(battlerAtk, battlerDef, move)
|
||||
&& gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE)
|
||||
ADJUST_SCORE(-10); // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you
|
||||
|
||||
@ -2278,7 +2280,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_ME_FIRST:
|
||||
if (predictedMove != MOVE_NONE)
|
||||
{
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER)
|
||||
if (AI_IsSlower(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(-10); // Target is predicted to go first, Me First will fail
|
||||
else
|
||||
return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score);
|
||||
@ -2461,7 +2463,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
break;
|
||||
case EFFECT_ELECTRIFY:
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER
|
||||
if (AI_IsSlower(battlerAtk, battlerDef, move)
|
||||
//|| GetMoveTypeSpecial(battlerDef, predictedMove) == TYPE_ELECTRIC // Move will already be electric type
|
||||
|| PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
@ -2490,7 +2492,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_INSTRUCT:
|
||||
{
|
||||
u16 instructedMove;
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER)
|
||||
if (AI_IsSlower(battlerAtk, battlerDef, move))
|
||||
instructedMove = predictedMove;
|
||||
else
|
||||
instructedMove = gLastMoves[battlerDef];
|
||||
@ -2529,21 +2531,21 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_QUASH:
|
||||
if (!isDoubleBattle
|
||||
|| AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER
|
||||
|| AI_IsSlower(battlerAtk, battlerDef, move)
|
||||
|| PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_AFTER_YOU:
|
||||
if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef)
|
||||
|| !isDoubleBattle
|
||||
|| AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER
|
||||
|| AI_IsSlower(battlerAtk, battlerDef, move)
|
||||
|| PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_SUCKER_PUNCH:
|
||||
if (predictedMove != MOVE_NONE)
|
||||
{
|
||||
if (IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Opponent going first
|
||||
if (IS_MOVE_STATUS(predictedMove) || AI_IsSlower(battlerAtk, battlerDef, move)) // Opponent going first
|
||||
ADJUST_SCORE(-10);
|
||||
}
|
||||
break;
|
||||
@ -2585,8 +2587,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-1);
|
||||
break;
|
||||
case EFFECT_FLAIL:
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER // Opponent should go first
|
||||
|| aiData->hpPercents[battlerAtk] > 50)
|
||||
if (AI_IsSlower(battlerAtk, battlerDef, move) // Opponent should go first
|
||||
|| aiData->hpPercents[battlerAtk] > 50)
|
||||
ADJUST_SCORE(-4);
|
||||
break;
|
||||
//TODO
|
||||
@ -2622,7 +2624,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
else if (CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
ADJUST_SCORE(-10);
|
||||
else if (CanTargetFaintAi(battlerDef, battlerAtk)
|
||||
&& AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER)
|
||||
&& AI_IsSlower(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_JUNGLE_HEALING:
|
||||
@ -2650,7 +2652,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_UPPER_HAND:
|
||||
if (predictedMove == MOVE_NONE || IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER || GetMovePriority(battlerDef, move) < 1 || GetMovePriority(battlerDef, move) > 3) // Opponent going first or not using priority move
|
||||
if (predictedMove == MOVE_NONE || IS_MOVE_STATUS(predictedMove) || AI_IsSlower(battlerAtk, battlerDef, move) || GetMovePriority(battlerDef, move) < 1 || GetMovePriority(battlerDef, move) > 3) // Opponent going first or not using priority move
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_PLACEHOLDER:
|
||||
@ -2675,7 +2677,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|
||||
if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, movesetIndex, 0) && gMovesInfo[move].effect != EFFECT_EXPLOSION)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(FAST_KILL);
|
||||
else
|
||||
ADJUST_SCORE(SLOW_KILL);
|
||||
@ -2741,7 +2743,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
// Adjust for always crit moves
|
||||
if (gMovesInfo[aiData->partnerMove].alwaysCriticalHit && aiData->abilities[battlerAtk] == ABILITY_ANGER_POINT)
|
||||
{
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_SLOWER) // Partner moving first
|
||||
if (AI_IsSlower(battlerAtk, battlerAtkPartner, move)) // Partner moving first
|
||||
{
|
||||
// discourage raising our attack since it's about to be maxed out
|
||||
if (IsAttackBoostMoveEffect(effect))
|
||||
@ -3021,7 +3023,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_INSTRUCT:
|
||||
{
|
||||
u16 instructedMove;
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_FASTER)
|
||||
if (AI_IsFaster(battlerAtk, battlerAtkPartner, move))
|
||||
instructedMove = aiData->partnerMove;
|
||||
else
|
||||
instructedMove = gLastMoves[battlerAtkPartner];
|
||||
@ -3035,8 +3037,8 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
break;
|
||||
case EFFECT_AFTER_YOU:
|
||||
if (AI_WhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), aiData->partnerMove) == AI_IS_SLOWER // Opponent mon 1 goes before partner
|
||||
|| AI_WhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), aiData->partnerMove) == AI_IS_SLOWER) // Opponent mon 2 goes before partner
|
||||
if (AI_IsSlower(battlerAtkPartner, FOE(battlerAtkPartner), aiData->partnerMove) // Opponent mon 1 goes before partner
|
||||
|| AI_IsSlower(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), aiData->partnerMove)) // Opponent mon 2 goes before partner
|
||||
{
|
||||
if (gMovesInfo[aiData->partnerMove].effect == EFFECT_COUNTER || gMovesInfo[aiData->partnerMove].effect == EFFECT_MIRROR_COAT)
|
||||
break; // These moves need to go last
|
||||
@ -3045,9 +3047,9 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_HEAL_PULSE:
|
||||
case EFFECT_HIT_ENEMY_HEAL_ALLY:
|
||||
if (AI_WhoStrikesFirst(battlerAtk, FOE(battlerAtk), move) == AI_IS_FASTER
|
||||
&& AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(FOE(battlerAtk)), move) == AI_IS_FASTER
|
||||
&& gBattleMons[battlerAtkPartner].hp < gBattleMons[battlerAtkPartner].maxHP / 2)
|
||||
if (AI_IsFaster(battlerAtk, FOE(battlerAtk), move)
|
||||
&& AI_IsFaster(battlerAtk, BATTLE_PARTNER(FOE(battlerAtk)), move)
|
||||
&& gBattleMons[battlerAtkPartner].hp < gBattleMons[battlerAtkPartner].maxHP / 2)
|
||||
RETURN_SCORE_PLUS(WEAK_EFFECT);
|
||||
break;
|
||||
} // attacker move effects
|
||||
@ -3154,7 +3156,7 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId)
|
||||
isTwoTurnNotSemiInvulnerableMove[i] = FALSE;
|
||||
}
|
||||
/*
|
||||
MgbaPrintf_("%S: required hits: %d Dmg: %d", gMoveNames[moves[i]], noOfHits[i], AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]);
|
||||
Test_MgbaPrintf("%S: required hits: %d Dmg: %d", gMoveNames[moves[i]], noOfHits[i], AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]);
|
||||
*/
|
||||
}
|
||||
|
||||
@ -3341,7 +3343,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
break;
|
||||
case EFFECT_SPEED_DOWN:
|
||||
case EFFECT_SPEED_DOWN_2:
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(-3);
|
||||
else if (!AI_RandLessThan(70))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
@ -3556,7 +3558,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(WEAK_EFFECT);
|
||||
break;
|
||||
case EFFECT_MIMIC:
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
{
|
||||
if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF)
|
||||
return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score);
|
||||
@ -3618,7 +3620,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
&& (gLastMoves[battlerDef] != MOVE_NONE)
|
||||
&& (gLastMoves[battlerDef] != 0xFFFF)
|
||||
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
|
||||
&& (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER))
|
||||
&& (AI_IsFaster(battlerAtk, battlerDef, move)))
|
||||
{
|
||||
if (CanTargetMoveFaintAi(gLastMoves[battlerDef], battlerDef, battlerAtk, 1))
|
||||
ADJUST_SCORE(GOOD_EFFECT); // Disable move that can kill attacker
|
||||
@ -3646,7 +3648,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
case EFFECT_DESTINY_BOND:
|
||||
if (IsDynamaxed(battlerDef))
|
||||
break;
|
||||
else if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
else if (AI_IsFaster(battlerAtk, battlerDef, move) && CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_SPITE:
|
||||
@ -3846,7 +3848,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
case EFFECT_SEMI_INVULNERABLE:
|
||||
if (predictedMove != MOVE_NONE && !isDoubleBattle)
|
||||
{
|
||||
if ((AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
|
||||
if ((AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
&& (gMovesInfo[predictedMove].effect == EFFECT_EXPLOSION || gMovesInfo[predictedMove].effect == EFFECT_PROTECT))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
else if (gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE))
|
||||
@ -3888,7 +3890,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
break;
|
||||
case EFFECT_ATTRACT:
|
||||
if (!isDoubleBattle
|
||||
&& (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER)
|
||||
&& (AI_IsSlower(battlerAtk, battlerDef, move))
|
||||
&& BattlerWillFaintFromSecondaryDamage(battlerDef, aiData->abilities[battlerDef]))
|
||||
break; // Don't use if the attract won't have a change to activate
|
||||
if (gBattleMons[battlerDef].status1 & STATUS1_ANY
|
||||
@ -3922,7 +3924,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
if (isDoubleBattle)
|
||||
{
|
||||
if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // Partner is going to set up hazards
|
||||
&& AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(battlerAtk), move) == AI_IS_SLOWER) // Partner going first
|
||||
&& AI_IsSlower(battlerAtk, BATTLE_PARTNER(battlerAtk), move)) // Partner going first
|
||||
break; // Don't use Defog if partner is going to set up hazards
|
||||
}
|
||||
if (ShouldLowerEvasion(battlerAtk, battlerDef, aiData->abilities[battlerDef]))
|
||||
@ -4083,6 +4085,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(WEAK_EFFECT); // Recycle healing berry if we can't otherwise faint the target and the target wont kill us after we activate the berry
|
||||
}
|
||||
break;
|
||||
case EFFECT_RAGING_BULL:
|
||||
case EFFECT_BRICK_BREAK:
|
||||
if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_REFLECT)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
@ -4348,7 +4351,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_HEAL_BLOCK:
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && predictedMove != MOVE_NONE && IsHealingMove(predictedMove))
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move) && predictedMove != MOVE_NONE && IsHealingMove(predictedMove))
|
||||
ADJUST_SCORE(DECENT_EFFECT); // Try to cancel healing move
|
||||
else if (HasHealingEffect(battlerDef) || aiData->holdEffects[battlerDef] == HOLD_EFFECT_LEFTOVERS
|
||||
|| (aiData->holdEffects[battlerDef] == HOLD_EFFECT_BLACK_SLUDGE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON)))
|
||||
@ -4380,7 +4383,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(BEST_EFFECT);
|
||||
break;
|
||||
case EFFECT_QUASH:
|
||||
if (isDoubleBattle && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerDef, aiData->partnerMove) == AI_IS_SLOWER)
|
||||
if (isDoubleBattle && AI_IsSlower(BATTLE_PARTNER(battlerAtk), battlerDef, aiData->partnerMove))
|
||||
ADJUST_SCORE(DECENT_EFFECT); // Attacker partner wouldn't go before target
|
||||
break;
|
||||
case EFFECT_TAILWIND:
|
||||
@ -4395,7 +4398,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
if (IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC)
|
||||
&& !(AI_GetTypeEffectiveness(MOVE_EARTHQUAKE, battlerDef, battlerAtk) == AI_EFFECTIVENESS_x0)) // Doesn't resist ground move
|
||||
{
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker goes first
|
||||
{
|
||||
if (gMovesInfo[predictedMove].type == TYPE_GROUND)
|
||||
ADJUST_SCORE(GOOD_EFFECT); // Cause the enemy's move to fail
|
||||
@ -4410,7 +4413,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
break;
|
||||
case EFFECT_CAMOUFLAGE:
|
||||
if (predictedMove != MOVE_NONE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER // Attacker goes first
|
||||
if (predictedMove != MOVE_NONE && AI_IsFaster(battlerAtk, battlerDef, move) // Attacker goes first
|
||||
&& !IS_MOVE_STATUS(move) && AI_GetTypeEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
@ -4446,7 +4449,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
break;
|
||||
case EFFECT_ENDEAVOR:
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER && !CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
if (AI_IsSlower(battlerAtk, battlerDef, move) && !CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_REVIVAL_BLESSING:
|
||||
@ -4706,7 +4709,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
case MOVE_EFFECT_THROAT_CHOP:
|
||||
if (gMovesInfo[GetBestDmgMoveFromBattler(battlerDef, battlerAtk)].soundMove)
|
||||
{
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
else
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
@ -4720,14 +4723,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
}
|
||||
|
||||
if (score <= 1)
|
||||
return NOT_GOOD_ENOUGH;
|
||||
else if (score <= 3)
|
||||
return GOOD_MOVE_EFFECTS;
|
||||
else if (score <= 5)
|
||||
return PREFERRED_MOVE_EFFECTS;
|
||||
else
|
||||
return BEST_MOVE_EFFECTS;
|
||||
return score;
|
||||
}
|
||||
|
||||
// AI_FLAG_CHECK_VIABILITY - Chooses best possible move to hit player
|
||||
@ -4742,7 +4738,12 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
||||
if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) == 0)
|
||||
ADJUST_SCORE(-20);
|
||||
else
|
||||
score += AI_CompareDamagingMoves(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex);
|
||||
{
|
||||
if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY) && GetBestDmgMoveFromBattler(battlerAtk, battlerDef) == move)
|
||||
score += 1;
|
||||
else
|
||||
score += AI_CompareDamagingMoves(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
score += AI_CalcMoveEffectScore(battlerAtk, battlerDef, move);
|
||||
@ -4759,7 +4760,7 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
||||
return score;
|
||||
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING
|
||||
&& AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER
|
||||
&& AI_IsSlower(battlerAtk, battlerDef, move)
|
||||
&& CanTargetFaintAi(battlerDef, battlerAtk)
|
||||
&& GetMovePriority(battlerAtk, move) == 0)
|
||||
{
|
||||
@ -4888,27 +4889,37 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (gMovesInfo[move].criticalHitStage > 0)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
|
||||
// +3 Score
|
||||
switch (gMovesInfo[move].effect)
|
||||
{
|
||||
case EFFECT_SLEEP:
|
||||
case EFFECT_EXPLOSION:
|
||||
case EFFECT_MIRROR_MOVE:
|
||||
case EFFECT_OHKO:
|
||||
case EFFECT_CONFUSE:
|
||||
case EFFECT_METRONOME:
|
||||
case EFFECT_PSYWAVE:
|
||||
case EFFECT_COUNTER:
|
||||
case EFFECT_DESTINY_BOND:
|
||||
case EFFECT_SWAGGER:
|
||||
case EFFECT_ATTRACT:
|
||||
case EFFECT_PRESENT:
|
||||
case EFFECT_BELLY_DRUM:
|
||||
if (gSpeciesInfo[gBattleMons[battlerDef].species].baseAttack >= gSpeciesInfo[gBattleMons[battlerDef].species].baseSpAttack + 10)
|
||||
ADJUST_SCORE(STRONG_RISKY_EFFECT);
|
||||
break;
|
||||
case EFFECT_MIRROR_COAT:
|
||||
case EFFECT_FOCUS_PUNCH:
|
||||
if (gSpeciesInfo[gBattleMons[battlerDef].species].baseSpAttack >= gSpeciesInfo[gBattleMons[battlerDef].species].baseAttack + 10)
|
||||
ADJUST_SCORE(STRONG_RISKY_EFFECT);
|
||||
break;
|
||||
case EFFECT_EXPLOSION:
|
||||
ADJUST_SCORE(STRONG_RISKY_EFFECT);
|
||||
break;
|
||||
|
||||
// +2 Score
|
||||
case EFFECT_REVENGE:
|
||||
case EFFECT_FILLET_AWAY:
|
||||
if (Random() & 1)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
if (gSpeciesInfo[gBattleMons[battlerDef].species].baseSpeed >= gSpeciesInfo[gBattleMons[battlerAtk].species].baseSpeed + 10)
|
||||
ADJUST_SCORE(AVERAGE_RISKY_EFFECT);
|
||||
break;
|
||||
case EFFECT_BELLY_DRUM:
|
||||
if (gBattleMons[battlerAtk].hp >= gBattleMons[battlerAtk].maxHP * 90 / 100)
|
||||
ADJUST_SCORE(AVERAGE_RISKY_EFFECT);
|
||||
break;
|
||||
case EFFECT_MAX_HP_50_RECOIL:
|
||||
case EFFECT_MIND_BLOWN:
|
||||
case EFFECT_SWAGGER:
|
||||
case EFFECT_FLATTER:
|
||||
case EFFECT_ATTRACT:
|
||||
case EFFECT_OHKO:
|
||||
ADJUST_SCORE(AVERAGE_RISKY_EFFECT);
|
||||
break;
|
||||
case EFFECT_HIT:
|
||||
{
|
||||
@ -4920,7 +4931,7 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
case MOVE_EFFECT_ALL_STATS_UP:
|
||||
if (Random() & 1)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
ADJUST_SCORE(AVERAGE_RISKY_EFFECT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -29,6 +29,7 @@ static bool32 AiExpectsToFaintPlayer(u32 battler);
|
||||
static bool32 AI_ShouldHeal(u32 battler, u32 healAmount);
|
||||
static bool32 AI_OpponentCanFaintAiWithMod(u32 battler, u32 healAmount);
|
||||
static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon);
|
||||
static bool32 CanAbilityTrapOpponent(u16 ability, u32 opponent);
|
||||
|
||||
static void InitializeSwitchinCandidate(struct Pokemon *mon)
|
||||
{
|
||||
@ -162,7 +163,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
|
||||
// Check if current mon can outspeed and KO in spite of bad matchup, and don't switch out if it can
|
||||
if(damageDealt > gBattleMons[opposingBattler].hp)
|
||||
{
|
||||
if (AI_WhoStrikesFirst(battler, opposingBattler, aiBestMove) == AI_IS_FASTER)
|
||||
if (AI_IsFaster(battler, opposingBattler, aiBestMove))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -414,6 +415,48 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler, bool32 emitResult)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool32 FindMonThatTrapsOpponent(u32 battler, bool32 emitResult)
|
||||
{
|
||||
s32 firstId;
|
||||
s32 lastId;
|
||||
struct Pokemon *party;
|
||||
s32 i;
|
||||
u16 monAbility;
|
||||
s32 opposingBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(battler)));
|
||||
|
||||
// Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer
|
||||
if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING))
|
||||
return FALSE;
|
||||
|
||||
// Check if current mon has an ability that traps opponent
|
||||
if (CanAbilityTrapOpponent(gBattleMons[battler].ability, opposingBattler))
|
||||
return FALSE;
|
||||
|
||||
// Check party for mon with ability that traps opponent
|
||||
GetAIPartyIndexes(battler, &firstId, &lastId);
|
||||
|
||||
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
|
||||
party = gPlayerParty;
|
||||
else
|
||||
party = gEnemyParty;
|
||||
|
||||
for (i = firstId; i < lastId; i++)
|
||||
{
|
||||
monAbility = GetMonAbility(&party[i]);
|
||||
if (CanAbilityTrapOpponent(monAbility, opposingBattler))
|
||||
{
|
||||
if (i == AI_DATA->mostSuitableMonId[battler]) // If mon in slot i is the most suitable switchin candidate, then it's a trapper than wins 1v1
|
||||
{
|
||||
gBattleStruct->AI_monToSwitchIntoId[battler] = i;
|
||||
if (emitResult)
|
||||
BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
|
||||
{
|
||||
bool32 switchMon = FALSE;
|
||||
@ -569,7 +612,7 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
|
||||
&& AnyStatIsRaised(battler))
|
||||
switchMon = FALSE;
|
||||
if (AiExpectsToFaintPlayer(battler)
|
||||
&& !AI_STRIKES_FIRST(battler, opposingBattler, 0)
|
||||
&& AI_IsSlower(battler, opposingBattler, 0)
|
||||
&& !AI_OpponentCanFaintAiWithMod(battler, 0))
|
||||
switchMon = FALSE;
|
||||
}
|
||||
@ -1017,6 +1060,8 @@ bool32 ShouldSwitch(u32 battler, bool32 emitResult)
|
||||
return TRUE;
|
||||
if (ShouldSwitchIfGameStatePrompt(battler, emitResult))
|
||||
return TRUE;
|
||||
if (FindMonThatTrapsOpponent(battler, emitResult))
|
||||
return TRUE;
|
||||
if (FindMonThatAbsorbsOpponentsMove(battler, emitResult))
|
||||
return TRUE;
|
||||
|
||||
@ -1234,7 +1279,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
|
||||
if (aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0)
|
||||
{
|
||||
aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j);
|
||||
dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_AVERAGE);
|
||||
dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_DEFAULT);
|
||||
if (bestDmg < dmg)
|
||||
{
|
||||
bestDmg = dmg;
|
||||
@ -1691,6 +1736,25 @@ static s32 GetMaxDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposingBattle
|
||||
return maxDamageTaken;
|
||||
}
|
||||
|
||||
static bool32 CanAbilityTrapOpponent(u16 ability, u32 opponent)
|
||||
{
|
||||
if ((B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(opponent, TYPE_GHOST)))
|
||||
return FALSE;
|
||||
else if (ability == ABILITY_SHADOW_TAG)
|
||||
{
|
||||
if (B_SHADOW_TAG_ESCAPE >= GEN_4 && GetBattlerAbility(opponent) == ABILITY_SHADOW_TAG) // Check if ability exists in species
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
else if (ability == ABILITY_ARENA_TRAP && IsBattlerGrounded(opponent))
|
||||
return TRUE;
|
||||
else if (ability == ABILITY_MAGNET_PULL && IS_BATTLER_OF_TYPE(opponent, TYPE_STEEL))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// This function splits switching behaviour mid-battle from after a KO.
|
||||
// Mid battle, it integrates GetBestMonTypeMatchup (vanilla with modifications), GetBestMonDefensive (custom), and GetBestMonBatonPass (vanilla with modifications)
|
||||
// After a KO, integrates GetBestMonRevengeKiller (custom), GetBestMonTypeMatchup (vanilla with modifications), GetBestMonBatonPass (vanilla with modifications), and GetBestMonDmg (vanilla)
|
||||
@ -1704,17 +1768,17 @@ static s32 GetMaxDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposingBattle
|
||||
static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, u32 battler, u32 opposingBattler, u8 battlerIn1, u8 battlerIn2, bool32 isSwitchAfterKO)
|
||||
{
|
||||
int revengeKillerId = PARTY_SIZE, slowRevengeKillerId = PARTY_SIZE, fastThreatenId = PARTY_SIZE, slowThreatenId = PARTY_SIZE, damageMonId = PARTY_SIZE;
|
||||
int batonPassId = PARTY_SIZE, typeMatchupId = PARTY_SIZE, typeMatchupEffectiveId = PARTY_SIZE, defensiveMonId = PARTY_SIZE, aceMonId = PARTY_SIZE;
|
||||
int batonPassId = PARTY_SIZE, typeMatchupId = PARTY_SIZE, typeMatchupEffectiveId = PARTY_SIZE, defensiveMonId = PARTY_SIZE, aceMonId = PARTY_SIZE, trapperId = PARTY_SIZE;
|
||||
int i, j, aliveCount = 0, bits = 0;
|
||||
s32 defensiveMonHitKOThreshold = 3; // 3HKO threshold that candidate defensive mons must exceed
|
||||
u32 aiMove, hitsToKO, hitsToKOThreshold, maxHitsToKO = 0;
|
||||
s32 playerMonSpeed = gBattleMons[opposingBattler].speed, playerMonHP = gBattleMons[opposingBattler].hp, aiMonSpeed, maxDamageDealt = 0, damageDealt = 0;
|
||||
u32 aiMove, hitsToKOAI, hitsToKOPlayer, hitsToKOAIThreshold, maxHitsToKO = 0;
|
||||
s32 playerMonSpeed = gBattleMons[opposingBattler].speed, playerMonHP = gBattleMons[opposingBattler].hp, aiMonSpeed, aiMovePriority = 0, maxDamageDealt = 0, damageDealt = 0;
|
||||
u16 bestResist = UQ_4_12(1.0), bestResistEffective = UQ_4_12(1.0), typeMatchup;
|
||||
|
||||
if (isSwitchAfterKO)
|
||||
hitsToKOThreshold = 1; // After a KO, mons at minimum need to not be 1-shot, as they switch in for free
|
||||
hitsToKOAIThreshold = 1; // After a KO, mons at minimum need to not be 1-shot, as they switch in for free
|
||||
else
|
||||
hitsToKOThreshold = 2; // When switching in otherwise need to not be 2-shot, as they do not switch in for free
|
||||
hitsToKOAIThreshold = 2; // When switching in otherwise need to not be 2-shot, as they do not switch in for free
|
||||
|
||||
// Iterate through mons
|
||||
for (i = firstId; i < lastId; i++)
|
||||
@ -1744,12 +1808,12 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
continue;
|
||||
|
||||
// Get max number of hits for player to KO AI mon
|
||||
hitsToKO = GetSwitchinHitsToKO(GetMaxDamagePlayerCouldDealToSwitchin(battler, opposingBattler, AI_DATA->switchinCandidate.battleMon), battler);
|
||||
hitsToKOAI = GetSwitchinHitsToKO(GetMaxDamagePlayerCouldDealToSwitchin(battler, opposingBattler, AI_DATA->switchinCandidate.battleMon), battler);
|
||||
|
||||
// Track max hits to KO and set GetBestMonDefensive if applicable
|
||||
if(hitsToKO > maxHitsToKO)
|
||||
if(hitsToKOAI > maxHitsToKO)
|
||||
{
|
||||
maxHitsToKO = hitsToKO;
|
||||
maxHitsToKO = hitsToKOAI;
|
||||
if(maxHitsToKO > defensiveMonHitKOThreshold)
|
||||
defensiveMonId = i;
|
||||
}
|
||||
@ -1759,7 +1823,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
// Check that good type matchups gets at least two turns and set GetBestMonTypeMatchup if applicable
|
||||
if (typeMatchup < bestResist)
|
||||
{
|
||||
if ((hitsToKO > hitsToKOThreshold && AI_DATA->switchinCandidate.battleMon.speed > playerMonSpeed) || hitsToKO > hitsToKOThreshold + 1) // Need to take an extra hit if slower
|
||||
if ((hitsToKOAI > hitsToKOAIThreshold && AI_DATA->switchinCandidate.battleMon.speed > playerMonSpeed) || hitsToKOAI > hitsToKOAIThreshold + 1) // Need to take an extra hit if slower
|
||||
{
|
||||
bestResist = typeMatchup;
|
||||
typeMatchupId = i;
|
||||
@ -1772,13 +1836,14 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
aiMove = AI_DATA->switchinCandidate.battleMon.moves[j];
|
||||
aiMovePriority = gMovesInfo[aiMove].priority;
|
||||
|
||||
// Only do damage calc if switching after KO, don't need it otherwise and saves ~0.02s per turn
|
||||
if (isSwitchAfterKO && aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0)
|
||||
damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_AVERAGE);
|
||||
damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_DEFAULT);
|
||||
|
||||
// Check for Baton Pass; hitsToKO requirements mean mon can boost and BP without dying whether it's slower or not
|
||||
if (aiMove == MOVE_BATON_PASS && ((hitsToKO > hitsToKOThreshold + 1 && AI_DATA->switchinCandidate.battleMon.speed < playerMonSpeed) || (hitsToKO > hitsToKOThreshold && AI_DATA->switchinCandidate.battleMon.speed > playerMonSpeed)))
|
||||
if (aiMove == MOVE_BATON_PASS && ((hitsToKOAI > hitsToKOAIThreshold + 1 && AI_DATA->switchinCandidate.battleMon.speed < playerMonSpeed) || (hitsToKOAI > hitsToKOAIThreshold && AI_DATA->switchinCandidate.battleMon.speed > playerMonSpeed)))
|
||||
bits |= gBitTable[i];
|
||||
|
||||
// Check for mon with resistance and super effective move for GetBestMonTypeMatchup
|
||||
@ -1789,7 +1854,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
if (AI_GetTypeEffectiveness(aiMove, battler, opposingBattler) >= UQ_4_12(2.0))
|
||||
{
|
||||
// Assuming a super effective move would do significant damage or scare the player out, so not being as conservative here
|
||||
if (hitsToKO > hitsToKOThreshold)
|
||||
if (hitsToKOAI > hitsToKOAIThreshold)
|
||||
{
|
||||
bestResistEffective = typeMatchup;
|
||||
typeMatchupEffectiveId = i;
|
||||
@ -1804,7 +1869,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
// Check that mon isn't one shot and set GetBestMonDmg if applicable
|
||||
if (damageDealt > maxDamageDealt)
|
||||
{
|
||||
if(hitsToKO > hitsToKOThreshold)
|
||||
if(hitsToKOAI > hitsToKOAIThreshold)
|
||||
{
|
||||
maxDamageDealt = damageDealt;
|
||||
damageMonId = i;
|
||||
@ -1816,7 +1881,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
if (damageDealt > playerMonHP)
|
||||
{
|
||||
// If AI mon is faster and doesn't die to hazards
|
||||
if ((aiMonSpeed > playerMonSpeed || gMovesInfo[aiMove].priority > 0) && AI_DATA->switchinCandidate.battleMon.hp > GetSwitchinHazardsDamage(battler, &AI_DATA->switchinCandidate.battleMon))
|
||||
if ((aiMonSpeed > playerMonSpeed || aiMovePriority > 0) && AI_DATA->switchinCandidate.battleMon.hp > GetSwitchinHazardsDamage(battler, &AI_DATA->switchinCandidate.battleMon))
|
||||
{
|
||||
// We have a revenge killer
|
||||
revengeKillerId = i;
|
||||
@ -1826,7 +1891,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
else
|
||||
{
|
||||
// If AI mon can't be OHKO'd
|
||||
if (hitsToKO > hitsToKOThreshold)
|
||||
if (hitsToKOAI > hitsToKOAIThreshold)
|
||||
{
|
||||
// We have a slow revenge killer
|
||||
slowRevengeKillerId = i;
|
||||
@ -1838,10 +1903,10 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
if (damageDealt > playerMonHP / 2)
|
||||
{
|
||||
// If AI mon is faster
|
||||
if (aiMonSpeed > playerMonSpeed || gMovesInfo[aiMove].priority > 0)
|
||||
if (aiMonSpeed > playerMonSpeed || aiMovePriority > 0)
|
||||
{
|
||||
// If AI mon can't be OHKO'd
|
||||
if (hitsToKO > hitsToKOThreshold)
|
||||
if (hitsToKOAI > hitsToKOAIThreshold)
|
||||
{
|
||||
// We have a fast threaten
|
||||
fastThreatenId = i;
|
||||
@ -1851,13 +1916,25 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
else
|
||||
{
|
||||
// If AI mon can't be 2HKO'd
|
||||
if (hitsToKO > hitsToKOThreshold + 1)
|
||||
if (hitsToKOAI > hitsToKOAIThreshold + 1)
|
||||
{
|
||||
// We have a slow threaten
|
||||
slowThreatenId = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If mon can trap
|
||||
if (CanAbilityTrapOpponent(AI_DATA->switchinCandidate.battleMon.ability, opposingBattler))
|
||||
{
|
||||
hitsToKOPlayer = GetNoOfHitsToKOBattlerDmg(damageDealt, opposingBattler);
|
||||
if (CountUsablePartyMons(opposingBattler) > 0
|
||||
&& (((hitsToKOAI > hitsToKOPlayer && isSwitchAfterKO) // If can 1v1 after a KO
|
||||
|| (hitsToKOAI == hitsToKOPlayer && isSwitchAfterKO && (aiMonSpeed > playerMonSpeed || aiMovePriority > 0)))
|
||||
|| ((hitsToKOAI > hitsToKOPlayer + 1 && !isSwitchAfterKO) // If can 1v1 after mid battle
|
||||
|| (hitsToKOAI == hitsToKOPlayer + 1 && !isSwitchAfterKO && (aiMonSpeed > playerMonSpeed || aiMovePriority > 0)))))
|
||||
trapperId = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1867,43 +1944,37 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
// Different switching priorities depending on switching mid battle vs switching after a KO
|
||||
if (isSwitchAfterKO)
|
||||
{
|
||||
// Return GetBestMonRevengeKiller > GetBestMonTypeMatchup > GetBestMonBatonPass > GetBestMonDmg
|
||||
if (revengeKillerId != PARTY_SIZE)
|
||||
// Return Trapper > GetBestMonRevengeKiller > GetBestMonTypeMatchup > GetBestMonBatonPass > GetBestMonDmg
|
||||
if (trapperId != PARTY_SIZE)
|
||||
return trapperId;
|
||||
else if (revengeKillerId != PARTY_SIZE)
|
||||
return revengeKillerId;
|
||||
|
||||
else if (slowRevengeKillerId != PARTY_SIZE)
|
||||
return slowRevengeKillerId;
|
||||
|
||||
else if (fastThreatenId != PARTY_SIZE)
|
||||
return fastThreatenId;
|
||||
|
||||
else if (slowThreatenId != PARTY_SIZE)
|
||||
return slowThreatenId;
|
||||
|
||||
else if (typeMatchupEffectiveId != PARTY_SIZE)
|
||||
return typeMatchupEffectiveId;
|
||||
|
||||
else if (typeMatchupId != PARTY_SIZE)
|
||||
return typeMatchupId;
|
||||
|
||||
else if (batonPassId != PARTY_SIZE)
|
||||
return batonPassId;
|
||||
|
||||
else if (damageMonId != PARTY_SIZE)
|
||||
return damageMonId;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return GetBestMonTypeMatchup > GetBestMonDefensive > GetBestMonBatonPass
|
||||
if (typeMatchupEffectiveId != PARTY_SIZE)
|
||||
// Return Trapper > GetBestMonTypeMatchup > GetBestMonDefensive > GetBestMonBatonPass
|
||||
if (trapperId != PARTY_SIZE)
|
||||
return trapperId;
|
||||
else if (typeMatchupEffectiveId != PARTY_SIZE)
|
||||
return typeMatchupEffectiveId;
|
||||
|
||||
else if (typeMatchupId != PARTY_SIZE)
|
||||
return typeMatchupId;
|
||||
|
||||
else if (defensiveMonId != PARTY_SIZE)
|
||||
return defensiveMonId;
|
||||
|
||||
else if (batonPassId != PARTY_SIZE)
|
||||
return batonPassId;
|
||||
|
||||
@ -2019,7 +2090,7 @@ static bool32 AiExpectsToFaintPlayer(u32 battler)
|
||||
|
||||
if (GetBattlerSide(target) != GetBattlerSide(battler)
|
||||
&& CanIndexMoveFaintTarget(battler, target, gBattleStruct->aiMoveOrAction[battler], 0)
|
||||
&& AI_WhoStrikesFirst(battler, target, GetAIChosenMove(battler)) == AI_IS_FASTER)
|
||||
&& AI_IsFaster(battler, target, GetAIChosenMove(battler)))
|
||||
{
|
||||
// We expect to faint the target and move first -> dont use an item
|
||||
return TRUE;
|
||||
|
||||
@ -35,6 +35,16 @@
|
||||
static u32 AI_GetEffectiveness(uq4_12_t multiplier);
|
||||
|
||||
// Functions
|
||||
bool32 AI_IsFaster(u32 battlerAi, u32 battlerDef, u32 move)
|
||||
{
|
||||
return (AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER);
|
||||
}
|
||||
|
||||
bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 move)
|
||||
{
|
||||
return (AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_SLOWER);
|
||||
}
|
||||
|
||||
u32 GetAIChosenMove(u32 battlerId)
|
||||
{
|
||||
return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]);
|
||||
@ -311,7 +321,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler)
|
||||
u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i];
|
||||
if (gMovesInfo[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE)
|
||||
return TRUE;
|
||||
if (gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAI, opposingBattler, GetAIChosenMove(battlerAI)) == AI_IS_SLOWER)
|
||||
if (gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE && AI_IsSlower(battlerAI, opposingBattler, GetAIChosenMove(battlerAI)))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@ -369,19 +379,21 @@ s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *type
|
||||
|
||||
static inline s32 LowestRollDmg(s32 dmg)
|
||||
{
|
||||
dmg *= 100 - 15;
|
||||
dmg *= MIN_ROLL_PERCENTAGE;
|
||||
dmg /= 100;
|
||||
return dmg;
|
||||
}
|
||||
|
||||
static inline s32 HighestRollDmg(s32 dmg)
|
||||
{
|
||||
dmg *= MAX_ROLL_PERCENTAGE;
|
||||
dmg /= 100;
|
||||
return dmg;
|
||||
}
|
||||
|
||||
static inline s32 AverageRollDmg(s32 dmg)
|
||||
static inline s32 DmgRoll(s32 dmg)
|
||||
{
|
||||
dmg = ((HighestRollDmg(dmg) + LowestRollDmg(dmg)) * 100) / 2;
|
||||
dmg *= DMG_ROLL_PERCENTAGE;
|
||||
dmg /= 100;
|
||||
return dmg;
|
||||
}
|
||||
@ -466,6 +478,14 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef)
|
||||
if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && gMovesInfo[move].argument == ARG_TRY_REMOVE_TERRAIN_FAIL)
|
||||
return TRUE;
|
||||
break;
|
||||
case EFFECT_POLTERGEIST:
|
||||
if (AI_DATA->items[battlerDef] == ITEM_NONE)
|
||||
return TRUE;
|
||||
break;
|
||||
case EFFECT_FIRST_TURN_ONLY:
|
||||
if (!gDisableStructs[battlerAtk].isFirstTurn)
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
@ -546,8 +566,8 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes
|
||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||
u32 critChance = GetCritHitChance(critChanceIndex);
|
||||
// With critChance getting closer to 1, dmg gets closer to critDmg.
|
||||
if (dmgRoll == DMG_ROLL_AVERAGE)
|
||||
dmg = AverageRollDmg((critDmg + normalDmg * (critChance - 1)) / (critChance));
|
||||
if (dmgRoll == DMG_ROLL_DEFAULT)
|
||||
dmg = DmgRoll((critDmg + normalDmg * (critChance - 1)) / (critChance));
|
||||
else if (dmgRoll == DMG_ROLL_HIGHEST)
|
||||
dmg = HighestRollDmg((critDmg + normalDmg * (critChance - 1)) / (critChance));
|
||||
else
|
||||
@ -555,8 +575,8 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dmgRoll == DMG_ROLL_AVERAGE)
|
||||
dmg = AverageRollDmg(normalDmg);
|
||||
if (dmgRoll == DMG_ROLL_DEFAULT)
|
||||
dmg = DmgRoll(normalDmg);
|
||||
else if (dmgRoll == DMG_ROLL_HIGHEST)
|
||||
dmg = HighestRollDmg(normalDmg);
|
||||
else
|
||||
@ -963,48 +983,21 @@ static u32 AI_GetEffectiveness(uq4_12_t multiplier)
|
||||
*/
|
||||
s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered)
|
||||
{
|
||||
u32 fasterAI = 0, fasterPlayer = 0, i;
|
||||
s8 prioAI = 0;
|
||||
s8 prioBattler2 = 0;
|
||||
u16 *battler2Moves = GetMovesArray(battler2);
|
||||
|
||||
// Check move priorities first.
|
||||
prioAI = GetMovePriority(battlerAI, moveConsidered);
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
prioBattler2 = GetMovePriority(battler2, battler2Moves[i]);
|
||||
if (battler2Moves[i] == MOVE_NONE || battler2Moves[i] == MOVE_UNAVAILABLE
|
||||
|| (prioBattler2 > prioAI && !CanIndexMoveFaintTarget(battler2, battlerAI, i , 2)))
|
||||
continue;
|
||||
|
||||
if (prioAI > prioBattler2)
|
||||
fasterAI++;
|
||||
else if (prioBattler2 > prioAI)
|
||||
fasterPlayer++;
|
||||
}
|
||||
|
||||
if (fasterAI > fasterPlayer)
|
||||
{
|
||||
if (prioAI > prioBattler2)
|
||||
return AI_IS_FASTER;
|
||||
|
||||
if (GetWhichBattlerFasterArgs(battlerAI, battler2, TRUE,
|
||||
AI_DATA->abilities[battlerAI], AI_DATA->abilities[battler2],
|
||||
AI_DATA->holdEffects[battlerAI], AI_DATA->holdEffects[battler2],
|
||||
AI_DATA->speedStats[battlerAI], AI_DATA->speedStats[battler2],
|
||||
prioAI, prioBattler2) == 1)
|
||||
return AI_IS_FASTER;
|
||||
}
|
||||
else if (fasterAI < fasterPlayer)
|
||||
{
|
||||
return AI_IS_SLOWER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prioAI > prioBattler2)
|
||||
return AI_IS_FASTER; // if we didn't know any of battler 2's moves to compare priorities, assume they don't have a prio+ move
|
||||
// Priorities are the same(at least comparing to moves the AI is aware of), decide by speed.
|
||||
if (GetWhichBattlerFasterArgs(battlerAI, battler2, TRUE,
|
||||
AI_DATA->abilities[battlerAI], AI_DATA->abilities[battler2],
|
||||
AI_DATA->holdEffects[battlerAI], AI_DATA->holdEffects[battler2],
|
||||
AI_DATA->speedStats[battlerAI], AI_DATA->speedStats[battler2],
|
||||
prioAI, prioBattler2) == 1)
|
||||
return AI_IS_FASTER;
|
||||
else
|
||||
return AI_IS_SLOWER;
|
||||
}
|
||||
return AI_IS_SLOWER;
|
||||
}
|
||||
|
||||
// Check if target has means to faint ai mon.
|
||||
@ -1612,7 +1605,7 @@ bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat)
|
||||
return !(battlerAbility == ABILITY_BIG_PECKS);
|
||||
case STAT_SPEED:
|
||||
// If AI is faster and doesn't have any mons left, lowering speed doesn't give any
|
||||
return !(AI_WhoStrikesFirst(sBattler_AI, battler, AI_THINKING_STRUCT->moveConsidered) == AI_IS_FASTER
|
||||
return !(AI_IsFaster(sBattler_AI, battler, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& CountUsablePartyMons(sBattler_AI) == 0
|
||||
&& !HasMoveEffect(sBattler_AI, EFFECT_ELECTRO_BALL));
|
||||
case STAT_ACC:
|
||||
@ -1681,7 +1674,7 @@ u32 CountNegativeStatStages(u32 battlerId)
|
||||
|
||||
bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
@ -1700,7 +1693,7 @@ bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
|
||||
bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
@ -1719,24 +1712,19 @@ bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
|
||||
bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
if (defAbility == ABILITY_CONTRARY
|
||||
|| defAbility == ABILITY_CLEAR_BODY
|
||||
|| defAbility == ABILITY_FULL_METAL_BODY
|
||||
|| defAbility == ABILITY_WHITE_SMOKE
|
||||
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET)
|
||||
return FALSE;
|
||||
|
||||
if (!AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& defAbility != ABILITY_CONTRARY
|
||||
&& defAbility != ABILITY_CLEAR_BODY
|
||||
&& defAbility != ABILITY_FULL_METAL_BODY
|
||||
&& defAbility != ABILITY_WHITE_SMOKE
|
||||
&& AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
return (AI_IsSlower(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered));
|
||||
}
|
||||
|
||||
bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
@ -1754,7 +1742,7 @@ bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
|
||||
bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
@ -1772,7 +1760,7 @@ bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
|
||||
bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
@ -1791,7 +1779,7 @@ bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
|
||||
bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility)
|
||||
{
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
|
||||
&& CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
@ -2512,7 +2500,7 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
|
||||
/*if (IsPredictedToSwitch(battlerDef, battlerAtk) && !hasStatBoost)
|
||||
return PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/
|
||||
|
||||
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker goes first
|
||||
{
|
||||
if (!CanAIFaintTarget(battlerAtk, battlerDef, 0)) // Can't KO foe otherwise
|
||||
{
|
||||
@ -2896,7 +2884,7 @@ u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbi
|
||||
if (((!IsMoldBreakerTypeAbility(AI_DATA->abilities[battlerAtk]) && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS))
|
||||
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|
||||
|| AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER)) // Opponent goes first
|
||||
|| AI_IsSlower(battlerAtk, battlerDef, move))) // Opponent goes first
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -2904,7 +2892,7 @@ u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbi
|
||||
|| gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS
|
||||
|| gBattleMons[battlerDef].status2 & STATUS2_INFATUATION
|
||||
|| gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
|
||||
|| ((AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) && CanTargetFaintAi(battlerDef, battlerAtk)))
|
||||
|| ((AI_IsFaster(battlerAtk, battlerDef, move)) && CanTargetFaintAi(battlerDef, battlerAtk)))
|
||||
{
|
||||
return 2; // good idea to flinch
|
||||
}
|
||||
@ -3022,7 +3010,7 @@ bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 mo
|
||||
|
||||
bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage)
|
||||
{
|
||||
if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
|
||||
if (move == 0xFFFF || AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
{
|
||||
// using item or user goes first
|
||||
u32 healPercent = (gMovesInfo[move].argument == 0) ? 50 : gMovesInfo[move].argument;
|
||||
@ -3049,7 +3037,7 @@ bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage)
|
||||
|
||||
bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent)
|
||||
{
|
||||
if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
|
||||
if (move == 0xFFFF || AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
{
|
||||
// using item or user going first
|
||||
s32 damage = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
|
||||
@ -3070,7 +3058,9 @@ bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect)
|
||||
{
|
||||
u32 atkSide = GetBattlerSide(battlerAtk);
|
||||
|
||||
if (HasMoveEffect(battlerDef, EFFECT_BRICK_BREAK)) // Don't waste a turn if screens will be broken
|
||||
// Don't waste a turn if screens will be broken
|
||||
if (HasMoveEffect(battlerDef, EFFECT_BRICK_BREAK)
|
||||
|| HasMoveEffect(battlerDef, EFFECT_RAGING_BULL))
|
||||
return FALSE;
|
||||
|
||||
switch (moveEffect)
|
||||
@ -3508,7 +3498,7 @@ bool32 IsRecycleEncouragedItem(u32 item)
|
||||
static void IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score, bool32 considerContrary)
|
||||
{
|
||||
u32 noOfHitsToFaint = NoOfHitsForTargetToFaintAI(battlerDef, battlerAtk);
|
||||
u32 aiIsFaster = GetWhichBattlerFaster(battlerAtk, battlerDef, TRUE) == AI_IS_FASTER;
|
||||
u32 aiIsFaster = AI_IsFaster(battlerAtk, battlerDef, TRUE);
|
||||
u32 shouldSetUp = ((noOfHitsToFaint >= 2 && aiIsFaster) || (noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS);
|
||||
|
||||
if (considerContrary && AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY)
|
||||
@ -3773,7 +3763,7 @@ bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove)
|
||||
else if (!IS_MOVE_STATUS(chosenMove) && IS_MOVE_STATUS(gBattleStruct->zmove.chosenZMove))
|
||||
return FALSE;
|
||||
|
||||
if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamageSaveBattlers(chosenMove, battlerAtk, battlerDef, &effectiveness, FALSE, DMG_ROLL_AVERAGE) >= gBattleMons[battlerDef].hp)
|
||||
if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamageSaveBattlers(chosenMove, battlerAtk, battlerDef, &effectiveness, FALSE, DMG_ROLL_DEFAULT) >= gBattleMons[battlerDef].hp)
|
||||
return FALSE; // don't waste damaging z move if can otherwise faint target
|
||||
|
||||
return TRUE;
|
||||
@ -3842,7 +3832,7 @@ void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerDef) != 0)
|
||||
ADJUST_SCORE_PTR(-2);
|
||||
|
||||
if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE && AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
|
||||
if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE && AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE_PTR(-10);
|
||||
if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE)
|
||||
ADJUST_SCORE_PTR(GOOD_EFFECT);
|
||||
@ -3888,6 +3878,6 @@ bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, st
|
||||
}
|
||||
|
||||
return (preventsStatLoss
|
||||
&& AI_STRIKES_FIRST(battlerAtk, battlerAtkPartner, TRUE)
|
||||
&& AI_IsFaster(battlerAtk, battlerAtkPartner, TRUE)
|
||||
&& HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL));
|
||||
}
|
||||
|
||||
@ -30,7 +30,6 @@
|
||||
|
||||
extern const u16 gMovesWithQuietBGM[];
|
||||
extern const u8 *const gBattleAnims_General[];
|
||||
extern const u8 *const gBattleAnims_Moves[];
|
||||
extern const u8 *const gBattleAnims_Special[];
|
||||
extern const u8 *const gBattleAnims_StatusConditions[];
|
||||
|
||||
@ -234,7 +233,6 @@ static void Nop(void)
|
||||
void LaunchBattleAnimation(u32 animType, u32 animId)
|
||||
{
|
||||
s32 i;
|
||||
const u8 *const *animsTable;
|
||||
|
||||
if (gTestRunnerEnabled)
|
||||
{
|
||||
@ -249,23 +247,6 @@ void LaunchBattleAnimation(u32 animType, u32 animId)
|
||||
}
|
||||
}
|
||||
|
||||
switch (animType)
|
||||
{
|
||||
case ANIM_TYPE_GENERAL:
|
||||
default:
|
||||
animsTable = gBattleAnims_General;
|
||||
break;
|
||||
case ANIM_TYPE_MOVE:
|
||||
animsTable = gBattleAnims_Moves;
|
||||
break;
|
||||
case ANIM_TYPE_STATUS:
|
||||
animsTable = gBattleAnims_StatusConditions;
|
||||
break;
|
||||
case ANIM_TYPE_SPECIAL:
|
||||
animsTable = gBattleAnims_Special;
|
||||
break;
|
||||
}
|
||||
|
||||
sAnimHideHpBoxes = !(animType == ANIM_TYPE_MOVE && animId == MOVE_TRANSFORM);
|
||||
if (animType != ANIM_TYPE_MOVE)
|
||||
{
|
||||
@ -322,7 +303,23 @@ void LaunchBattleAnimation(u32 animType, u32 animId)
|
||||
|
||||
sMonAnimTaskIdArray[0] = TASK_NONE;
|
||||
sMonAnimTaskIdArray[1] = TASK_NONE;
|
||||
sBattleAnimScriptPtr = animsTable[animId];
|
||||
|
||||
switch (animType)
|
||||
{
|
||||
case ANIM_TYPE_GENERAL:
|
||||
default:
|
||||
sBattleAnimScriptPtr = gBattleAnims_General[animId];
|
||||
break;
|
||||
case ANIM_TYPE_MOVE:
|
||||
sBattleAnimScriptPtr = GetMoveAnimationScript(animId);
|
||||
break;
|
||||
case ANIM_TYPE_STATUS:
|
||||
sBattleAnimScriptPtr = gBattleAnims_StatusConditions[animId];
|
||||
break;
|
||||
case ANIM_TYPE_SPECIAL:
|
||||
sBattleAnimScriptPtr = gBattleAnims_Special[animId];
|
||||
break;
|
||||
}
|
||||
gAnimScriptActive = TRUE;
|
||||
sAnimFramesToWait = 0;
|
||||
gAnimScriptCallback = RunAnimScriptCommand;
|
||||
|
||||
@ -371,6 +371,15 @@ static const struct WindowTemplate sStandardBattleWindowTemplates[] =
|
||||
.paletteNum = 0,
|
||||
.baseBlock = 0x00b0,
|
||||
},
|
||||
[B_WIN_MOVE_DESCRIPTION] = {
|
||||
.bg = 0,
|
||||
.tilemapLeft = 1,
|
||||
.tilemapTop = 47,
|
||||
.width = 18,
|
||||
.height = 6,
|
||||
.paletteNum = 5,
|
||||
.baseBlock = 0x0350,
|
||||
},
|
||||
DUMMY_WIN_TEMPLATE
|
||||
};
|
||||
|
||||
@ -583,6 +592,15 @@ static const struct WindowTemplate sBattleArenaWindowTemplates[] =
|
||||
.paletteNum = 7,
|
||||
.baseBlock = 0x0090,
|
||||
},
|
||||
[B_WIN_MOVE_DESCRIPTION] = {
|
||||
.bg = 0,
|
||||
.tilemapLeft = 1,
|
||||
.tilemapTop = 47,
|
||||
.width = 18,
|
||||
.height = 6,
|
||||
.paletteNum = 5,
|
||||
.baseBlock = 0x0350,
|
||||
},
|
||||
DUMMY_WIN_TEMPLATE
|
||||
};
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#include "util.h"
|
||||
#include "window.h"
|
||||
#include "constants/battle_anim.h"
|
||||
#include "constants/battle_move_effects.h"
|
||||
#include "constants/battle_partner.h"
|
||||
#include "constants/hold_effects.h"
|
||||
#include "constants/items.h"
|
||||
@ -40,6 +41,8 @@
|
||||
#include "constants/trainers.h"
|
||||
#include "constants/rgb.h"
|
||||
#include "level_caps.h"
|
||||
#include "menu.h"
|
||||
#include "pokemon_summary_screen.h"
|
||||
|
||||
static void PlayerBufferExecCompleted(u32 battler);
|
||||
static void PlayerHandleLoadMonSprite(u32 battler);
|
||||
@ -83,6 +86,7 @@ static void MoveSelectionDisplayPpNumber(u32 battler);
|
||||
static void MoveSelectionDisplayPpString(u32 battler);
|
||||
static void MoveSelectionDisplayMoveType(u32 battler);
|
||||
static void MoveSelectionDisplayMoveNames(u32 battler);
|
||||
static void MoveSelectionDisplayMoveDescription(u32 battler);
|
||||
static void HandleMoveSwitching(u32 battler);
|
||||
static void SwitchIn_HandleSoundAndEnd(u32 battler);
|
||||
static void WaitForMonSelection(u32 battler);
|
||||
@ -158,6 +162,8 @@ static void (*const sPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) =
|
||||
[CONTROLLER_TERMINATOR_NOP] = BtlController_TerminatorNop
|
||||
};
|
||||
|
||||
static EWRAM_DATA bool8 sDescriptionSubmenu = 0;
|
||||
|
||||
static EWRAM_DATA bool8 sAckBallUseBtn = FALSE;
|
||||
static EWRAM_DATA bool8 sBallSwapped = FALSE;
|
||||
|
||||
@ -690,7 +696,7 @@ static void HandleInputChooseMove(u32 battler)
|
||||
else
|
||||
gPlayerDpadHoldFrames = 0;
|
||||
|
||||
if (JOY_NEW(A_BUTTON))
|
||||
if (JOY_NEW(A_BUTTON) && !sDescriptionSubmenu)
|
||||
{
|
||||
PlaySE(SE_SELECT);
|
||||
|
||||
@ -797,7 +803,7 @@ static void HandleInputChooseMove(u32 battler)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(B_BUTTON) || gPlayerDpadHoldFrames > 59)
|
||||
else if ((JOY_NEW(B_BUTTON) || gPlayerDpadHoldFrames > 59) && !sDescriptionSubmenu)
|
||||
{
|
||||
PlaySE(SE_SELECT);
|
||||
if (gBattleStruct->zmove.viewing)
|
||||
@ -826,6 +832,8 @@ static void HandleInputChooseMove(u32 battler)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0);
|
||||
MoveSelectionDisplayPpNumber(battler);
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
if (sDescriptionSubmenu)
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
TryChangeZIndicator(battler, gMoveSelectionCursor[battler]);
|
||||
}
|
||||
}
|
||||
@ -840,6 +848,8 @@ static void HandleInputChooseMove(u32 battler)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0);
|
||||
MoveSelectionDisplayPpNumber(battler);
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
if (sDescriptionSubmenu)
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
TryChangeZIndicator(battler, gMoveSelectionCursor[battler]);
|
||||
}
|
||||
}
|
||||
@ -853,6 +863,8 @@ static void HandleInputChooseMove(u32 battler)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0);
|
||||
MoveSelectionDisplayPpNumber(battler);
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
if (sDescriptionSubmenu)
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
TryChangeZIndicator(battler, gMoveSelectionCursor[battler]);
|
||||
}
|
||||
}
|
||||
@ -867,10 +879,12 @@ static void HandleInputChooseMove(u32 battler)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0);
|
||||
MoveSelectionDisplayPpNumber(battler);
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
if (sDescriptionSubmenu)
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
TryChangeZIndicator(battler, gMoveSelectionCursor[battler]);
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(SELECT_BUTTON) && !gBattleStruct->zmove.viewing)
|
||||
else if (JOY_NEW(SELECT_BUTTON) && !gBattleStruct->zmove.viewing && !sDescriptionSubmenu)
|
||||
{
|
||||
if (gNumberOfMovesToChoose > 1 && !(gBattleTypeFlags & BATTLE_TYPE_LINK))
|
||||
{
|
||||
@ -886,6 +900,30 @@ static void HandleInputChooseMove(u32 battler)
|
||||
gBattlerControllerFuncs[battler] = HandleMoveSwitching;
|
||||
}
|
||||
}
|
||||
else if (sDescriptionSubmenu)
|
||||
{
|
||||
if (JOY_NEW(L_BUTTON) || JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON))
|
||||
{
|
||||
sDescriptionSubmenu = FALSE;
|
||||
if (gCategoryIconSpriteId != 0xFF)
|
||||
{
|
||||
DestroySprite(&gSprites[gCategoryIconSpriteId]);
|
||||
gCategoryIconSpriteId = 0xFF;
|
||||
}
|
||||
|
||||
FillWindowPixelBuffer(B_WIN_MOVE_DESCRIPTION, PIXEL_FILL(0));
|
||||
ClearStdWindowAndFrame(B_WIN_MOVE_DESCRIPTION, FALSE);
|
||||
CopyWindowToVram(B_WIN_MOVE_DESCRIPTION, COPYWIN_GFX);
|
||||
PlaySE(SE_SELECT);
|
||||
MoveSelectionDisplayPpNumber(battler);
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(L_BUTTON))
|
||||
{
|
||||
sDescriptionSubmenu = TRUE;
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
}
|
||||
else if (JOY_NEW(START_BUTTON))
|
||||
{
|
||||
if (CanMegaEvolve(battler))
|
||||
@ -1772,6 +1810,54 @@ static void MoveSelectionDisplayMoveType(u32 battler)
|
||||
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MOVE_TYPE);
|
||||
}
|
||||
|
||||
static void MoveSelectionDisplayMoveDescription(u32 battler)
|
||||
{
|
||||
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleResources->bufferA[battler][4]);
|
||||
u16 move = moveInfo->moves[gMoveSelectionCursor[battler]];
|
||||
u16 pwr = gMovesInfo[move].power;
|
||||
u16 acc = gMovesInfo[move].accuracy;
|
||||
u8 cat = gMovesInfo[move].category;
|
||||
|
||||
u8 pwr_num[3], acc_num[3];
|
||||
u8 cat_desc[7] = _("CAT: ");
|
||||
u8 pwr_desc[7] = _("PWR: ");
|
||||
u8 acc_desc[7] = _("ACC: ");
|
||||
u8 cat_start[] = _("{CLEAR_TO 0x03}");
|
||||
u8 pwr_start[] = _("{CLEAR_TO 0x38}");
|
||||
u8 acc_start[] = _("{CLEAR_TO 0x6D}");
|
||||
LoadMessageBoxAndBorderGfx();
|
||||
DrawStdWindowFrame(B_WIN_MOVE_DESCRIPTION, FALSE);
|
||||
if (pwr < 2)
|
||||
StringCopy(pwr_num, gText_BattleSwitchWhich5);
|
||||
else
|
||||
ConvertIntToDecimalStringN(pwr_num, pwr, STR_CONV_MODE_LEFT_ALIGN, 3);
|
||||
if (acc < 2)
|
||||
StringCopy(acc_num, gText_BattleSwitchWhich5);
|
||||
else
|
||||
ConvertIntToDecimalStringN(acc_num, acc, STR_CONV_MODE_LEFT_ALIGN, 3);
|
||||
StringCopy(gDisplayedStringBattle, cat_start);
|
||||
StringAppend(gDisplayedStringBattle, cat_desc);
|
||||
StringAppend(gDisplayedStringBattle, pwr_start);
|
||||
StringAppend(gDisplayedStringBattle, pwr_desc);
|
||||
StringAppend(gDisplayedStringBattle, pwr_num);
|
||||
StringAppend(gDisplayedStringBattle, acc_start);
|
||||
StringAppend(gDisplayedStringBattle, acc_desc);
|
||||
StringAppend(gDisplayedStringBattle, acc_num);
|
||||
StringAppend(gDisplayedStringBattle, gText_NewLine);
|
||||
if (gMovesInfo[move].effect == EFFECT_PLACEHOLDER)
|
||||
StringAppend(gDisplayedStringBattle, gNotDoneYetDescription);
|
||||
else
|
||||
StringAppend(gDisplayedStringBattle, gMovesInfo[move].description);
|
||||
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MOVE_DESCRIPTION);
|
||||
|
||||
if (gCategoryIconSpriteId == 0xFF)
|
||||
gCategoryIconSpriteId = CreateSprite(&gSpriteTemplate_CategoryIcons, 38, 64, 1);
|
||||
|
||||
StartSpriteAnim(&gSprites[gCategoryIconSpriteId], cat);
|
||||
|
||||
CopyWindowToVram(B_WIN_MOVE_DESCRIPTION, COPYWIN_FULL);
|
||||
}
|
||||
|
||||
void MoveSelectionCreateCursorAt(u8 cursorPosition, u8 baseTileNum)
|
||||
{
|
||||
u16 src[2];
|
||||
|
||||
@ -207,6 +207,7 @@ void UndoDynamax(u16 battlerId)
|
||||
u16 mult = UQ_4_12(1.0/1.5); // placeholder
|
||||
gBattleMons[battlerId].hp = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_HP) * mult + 1) + UQ_4_12_ROUND); // round up
|
||||
SetMonData(mon, MON_DATA_HP, &gBattleMons[battlerId].hp);
|
||||
CalculateMonStats(mon);
|
||||
}
|
||||
|
||||
// Makes sure there are no Dynamax flags set, including on switch / faint.
|
||||
|
||||
@ -707,6 +707,7 @@ bool8 BattleLoadAllHealthBoxesGfx(u8 state)
|
||||
LoadSpritePalette(&sSpritePalettes_HealthBoxHealthBar[1]);
|
||||
MegaIndicator_LoadSpritesGfx();
|
||||
TeraIndicator_LoadSpriteGfx();
|
||||
CategoryIcons_LoadSpritesGfx();
|
||||
}
|
||||
else if (!IsDoubleBattle())
|
||||
{
|
||||
|
||||
@ -3753,3 +3753,9 @@ void ArrowsChangeColorLastBallCycle(bool32 showArrows)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CategoryIcons_LoadSpritesGfx(void)
|
||||
{
|
||||
LoadCompressedSpriteSheet(&gSpriteSheet_CategoryIcons);
|
||||
LoadSpritePalette(&gSpritePal_CategoryIcons);
|
||||
}
|
||||
|
||||
@ -54,6 +54,7 @@
|
||||
#include "wild_encounter.h"
|
||||
#include "window.h"
|
||||
#include "constants/abilities.h"
|
||||
#include "constants/battle_ai.h"
|
||||
#include "constants/battle_move_effects.h"
|
||||
#include "constants/battle_string_ids.h"
|
||||
#include "constants/battle_partner.h"
|
||||
@ -229,6 +230,7 @@ EWRAM_DATA u16 gBallToDisplay = 0;
|
||||
EWRAM_DATA bool8 gLastUsedBallMenuPresent = FALSE;
|
||||
EWRAM_DATA u8 gPartyCriticalHits[PARTY_SIZE] = {0};
|
||||
EWRAM_DATA static u8 sTriedEvolving = 0;
|
||||
EWRAM_DATA u8 gCategoryIconSpriteId = 0;
|
||||
|
||||
void (*gPreBattleCallback1)(void);
|
||||
void (*gBattleMainFunc)(void);
|
||||
@ -294,336 +296,7 @@ const struct OamData gOamData_BattleSpritePlayerSide =
|
||||
|
||||
static const s8 sCenterToCornerVecXs[8] ={-32, -16, -16, -32, -32};
|
||||
|
||||
#if B_EXPANDED_TYPE_NAMES == TRUE
|
||||
#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(DEFAULT(_name, __VA_ARGS__))
|
||||
#else
|
||||
#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(_name)
|
||||
#endif
|
||||
|
||||
// .generic is large enough that the text for TYPE_ELECTRIC will exceed TEXT_BUFF_ARRAY_COUNT.
|
||||
const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] =
|
||||
{
|
||||
[TYPE_NORMAL] =
|
||||
{
|
||||
.name = _("Normal"),
|
||||
.generic = _("a NORMAL move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_BREAKNECK_BLITZ,
|
||||
.maxMove = MOVE_MAX_STRIKE,
|
||||
.paletteTMHM = gItemIconPalette_NormalTMHM,
|
||||
//.enhanceItem = ITEM_SILK_SCARF,
|
||||
//.berry = ITEM_CHILAN_BERRY,
|
||||
//.gem = ITEM_NORMAL_GEM,
|
||||
//.zCrystal = ITEM_NORMALIUM_Z,
|
||||
//.teraShard = ITEM_NORMAL_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_NORMAL,
|
||||
},
|
||||
[TYPE_FIGHTING] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_TYPE_NAME("Fight", "Fighting"),
|
||||
.generic = _("a FIGHTING move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_ALL_OUT_PUMMELING,
|
||||
.maxMove = MOVE_MAX_KNUCKLE,
|
||||
.paletteTMHM = gItemIconPalette_FightingTMHM,
|
||||
//.enhanceItem = ITEM_BLACK_BELT,
|
||||
//.berry = ITEM_CHOPLE_BERRY,
|
||||
//.gem = ITEM_FIGHTING_GEM,
|
||||
//.zCrystal = ITEM_FIGHTINIUM_Z,
|
||||
//.plate = ITEM_FIST_PLATE,
|
||||
//.memory = ITEM_FIGHTING_MEMORY,
|
||||
//.teraShard = ITEM_FIGHTING_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_FIGHTING,
|
||||
},
|
||||
[TYPE_FLYING] =
|
||||
{
|
||||
.name = _("Flying"),
|
||||
.generic = _("a FLYING move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_SUPERSONIC_SKYSTRIKE,
|
||||
.maxMove = MOVE_MAX_AIRSTREAM,
|
||||
.paletteTMHM = gItemIconPalette_FlyingTMHM,
|
||||
//.enhanceItem = ITEM_SHARP_BEAK,
|
||||
//.berry = ITEM_COBA_BERRY,
|
||||
//.gem = ITEM_FLYING_GEM,
|
||||
//.zCrystal = ITEM_FLYINIUM_Z,
|
||||
//.plate = ITEM_SKY_PLATE,
|
||||
//.memory = ITEM_FLYING_MEMORY,
|
||||
//.teraShard = ITEM_FLYING_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_FLYING,
|
||||
},
|
||||
[TYPE_POISON] =
|
||||
{
|
||||
.name = _("Poison"),
|
||||
.generic = _("a POISON move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_ACID_DOWNPOUR,
|
||||
.maxMove = MOVE_MAX_OOZE,
|
||||
.paletteTMHM = gItemIconPalette_PoisonTMHM,
|
||||
//.enhanceItem = ITEM_POISON_BARB,
|
||||
//.berry = ITEM_KEBIA_BERRY,
|
||||
//.gem = ITEM_POISON_GEM,
|
||||
//.zCrystal = ITEM_POISONIUM_Z,
|
||||
//.plate = ITEM_TOXIC_PLATE,
|
||||
//.memory = ITEM_POISON_MEMORY,
|
||||
//.teraShard = ITEM_POISON_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_POISON,
|
||||
},
|
||||
[TYPE_GROUND] =
|
||||
{
|
||||
.name = _("Ground"),
|
||||
.generic = _("a GROUND move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_TECTONIC_RAGE,
|
||||
.maxMove = MOVE_MAX_QUAKE,
|
||||
.paletteTMHM = gItemIconPalette_GroundTMHM,
|
||||
//.enhanceItem = ITEM_SOFT_SAND,
|
||||
//.berry = ITEM_SHUCA_BERRY,
|
||||
//.gem = ITEM_GROUND_GEM,
|
||||
//.zCrystal = ITEM_GROUNDIUM_Z,
|
||||
//.plate = ITEM_EARTH_PLATE,
|
||||
//.memory = ITEM_GROUND_MEMORY,
|
||||
//.teraShard = ITEM_GROUND_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_GROUND,
|
||||
},
|
||||
[TYPE_ROCK] =
|
||||
{
|
||||
.name = _("Rock"),
|
||||
.generic = _("a ROCK move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_CONTINENTAL_CRUSH,
|
||||
.maxMove = MOVE_MAX_ROCKFALL,
|
||||
.paletteTMHM = gItemIconPalette_RockTMHM,
|
||||
//.enhanceItem = ITEM_HARD_STONE,
|
||||
//.berry = ITEM_CHARTI_BERRY,
|
||||
//.gem = ITEM_ROCK_GEM,
|
||||
//.zCrystal = ITEM_ROCKIUM_Z,
|
||||
//.plate = ITEM_STONE_PLATE,
|
||||
//.memory = ITEM_ROCK_MEMORY,
|
||||
//.teraShard = ITEM_ROCK_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_ROCK,
|
||||
},
|
||||
[TYPE_BUG] =
|
||||
{
|
||||
.name = _("Bug"),
|
||||
.generic = _("a BUG move"),
|
||||
.palette = 15,
|
||||
.zMove = MOVE_SAVAGE_SPIN_OUT,
|
||||
.maxMove = MOVE_MAX_FLUTTERBY,
|
||||
.paletteTMHM = gItemIconPalette_BugTMHM,
|
||||
//.enhanceItem = ITEM_SILVER_POWDER,
|
||||
//.berry = ITEM_TANGA_BERRY,
|
||||
//.gem = ITEM_BUG_GEM,
|
||||
//.zCrystal = ITEM_BUGINIUM_Z,
|
||||
//.plate = ITEM_INSECT_PLATE,
|
||||
//.memory = ITEM_BUG_MEMORY,
|
||||
//.teraShard = ITEM_BUG_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_BUG,
|
||||
},
|
||||
[TYPE_GHOST] =
|
||||
{
|
||||
.name = _("Ghost"),
|
||||
.generic = _("a GHOST move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_NEVER_ENDING_NIGHTMARE,
|
||||
.maxMove = MOVE_MAX_PHANTASM,
|
||||
.paletteTMHM = gItemIconPalette_GhostTMHM,
|
||||
//.enhanceItem = ITEM_SPELL_TAG,
|
||||
//.berry = ITEM_KASIB_BERRY,
|
||||
//.gem = ITEM_GHOST_GEM,
|
||||
//.zCrystal = ITEM_GHOSTIUM_Z,
|
||||
//.plate = ITEM_SPOOKY_PLATE,
|
||||
//.memory = ITEM_GHOST_MEMORY,
|
||||
//.teraShard = ITEM_GHOST_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_GHOST,
|
||||
},
|
||||
[TYPE_STEEL] =
|
||||
{
|
||||
.name = _("Steel"),
|
||||
.generic = _("a STEEL move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_CORKSCREW_CRASH,
|
||||
.maxMove = MOVE_MAX_STEELSPIKE,
|
||||
.paletteTMHM = gItemIconPalette_SteelTMHM,
|
||||
//.enhanceItem = ITEM_METAL_COAT,
|
||||
//.berry = ITEM_BABIRI_BERRY,
|
||||
//.gem = ITEM_STEEL_GEM,
|
||||
//.zCrystal = ITEM_STEELIUM_Z,
|
||||
//.plate = ITEM_IRON_PLATE,
|
||||
//.memory = ITEM_STEEL_MEMORY,
|
||||
//.teraShard = ITEM_STEEL_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_STEEL,
|
||||
},
|
||||
[TYPE_MYSTERY] =
|
||||
{
|
||||
.name = _("???"),
|
||||
.generic = _("a ??? move"),
|
||||
.palette = 15,
|
||||
},
|
||||
[TYPE_FIRE] =
|
||||
{
|
||||
.name = _("Fire"),
|
||||
.generic = _("a FIRE move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_INFERNO_OVERDRIVE,
|
||||
.maxMove = MOVE_MAX_FLARE,
|
||||
.paletteTMHM = gItemIconPalette_FireTMHM,
|
||||
//.enhanceItem = ITEM_CHARCOAL,
|
||||
//.berry = ITEM_OCCA_BERRY,
|
||||
//.gem = ITEM_FIRE_GEM,
|
||||
//.zCrystal = ITEM_FIRIUM_Z,
|
||||
//.plate = ITEM_FLAME_PLATE,
|
||||
//.memory = ITEM_FIRE_MEMORY,
|
||||
//.teraShard = ITEM_FIRE_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_FIRE,
|
||||
},
|
||||
[TYPE_WATER] =
|
||||
{
|
||||
.name = _("Water"),
|
||||
.generic = _("a WATER move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_HYDRO_VORTEX,
|
||||
.maxMove = MOVE_MAX_GEYSER,
|
||||
.paletteTMHM = gItemIconPalette_WaterTMHM,
|
||||
//.enhanceItem = ITEM_MYSTIC_WATER,
|
||||
//.berry = ITEM_PASSHO_BERRY,
|
||||
//.gem = ITEM_WATER_GEM,
|
||||
//.zCrystal = ITEM_WATERIUM_Z,
|
||||
//.plate = ITEM_SPLASH_PLATE,
|
||||
//.memory = ITEM_WATER_MEMORY,
|
||||
//.teraShard = ITEM_WATER_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_WATER,
|
||||
},
|
||||
[TYPE_GRASS] =
|
||||
{
|
||||
.name = _("Grass"),
|
||||
.generic = _("a GRASS move"),
|
||||
.palette = 15,
|
||||
.zMove = MOVE_BLOOM_DOOM,
|
||||
.maxMove = MOVE_MAX_OVERGROWTH,
|
||||
.paletteTMHM = gItemIconPalette_GrassTMHM,
|
||||
//.enhanceItem = ITEM_MIRACLE_SEED,
|
||||
//.berry = ITEM_RINDO_BERRY,
|
||||
//.gem = ITEM_GRASS_GEM,
|
||||
//.zCrystal = ITEM_GRASSIUM_Z,
|
||||
//.plate = ITEM_MEADOW_PLATE,
|
||||
//.memory = ITEM_GRASS_MEMORY,
|
||||
//.teraShard = ITEM_GRASS_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_GRASS,
|
||||
},
|
||||
[TYPE_ELECTRIC] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_TYPE_NAME("Electr", "Electric"),
|
||||
.generic = _("an ELECTRIC move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_GIGAVOLT_HAVOC,
|
||||
.maxMove = MOVE_MAX_LIGHTNING,
|
||||
.paletteTMHM = gItemIconPalette_ElectricTMHM,
|
||||
//.enhanceItem = ITEM_MAGNET,
|
||||
//.berry = ITEM_WACAN_BERRY,
|
||||
//.gem = ITEM_ELECTRIC_GEM,
|
||||
//.zCrystal = ITEM_ELECTRIUM_Z,
|
||||
//.plate = ITEM_ZAP_PLATE,
|
||||
//.memory = ITEM_ELECTRIC_MEMORY,
|
||||
//.teraShard = ITEM_ELECTRIC_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_ELECTRIC,
|
||||
},
|
||||
[TYPE_PSYCHIC] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_TYPE_NAME("Psychc", "Psychic"),
|
||||
.generic = _("a PSYCHIC move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_SHATTERED_PSYCHE,
|
||||
.maxMove = MOVE_MAX_MINDSTORM,
|
||||
.paletteTMHM = gItemIconPalette_PsychicTMHM,
|
||||
//.enhanceItem = ITEM_TWISTED_SPOON,
|
||||
//.berry = ITEM_PAYAPA_BERRY,
|
||||
//.gem = ITEM_PSYCHIC_GEM,
|
||||
//.zCrystal = ITEM_PSYCHIUM_Z,
|
||||
//.plate = ITEM_MIND_PLATE,
|
||||
//.memory = ITEM_PSYCHIC_MEMORY,
|
||||
//.teraShard = ITEM_PSYCHIC_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_PSYCHIC,
|
||||
},
|
||||
[TYPE_ICE] =
|
||||
{
|
||||
.name = _("Ice"),
|
||||
.generic = _("an ICE move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_SUBZERO_SLAMMER,
|
||||
.maxMove = MOVE_MAX_HAILSTORM,
|
||||
.paletteTMHM = gItemIconPalette_IceTMHM,
|
||||
//.enhanceItem = ITEM_NEVER_MELT_ICE,
|
||||
//.berry = ITEM_YACHE_BERRY,
|
||||
//.gem = ITEM_ICE_GEM,
|
||||
//.zCrystal = ITEM_ICIUM_Z,
|
||||
//.plate = ITEM_ICICLE_PLATE,
|
||||
//.memory = ITEM_ICE_MEMORY,
|
||||
//.teraShard = ITEM_ICE_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_ICE,
|
||||
},
|
||||
[TYPE_DRAGON] =
|
||||
{
|
||||
.name = _("Dragon"),
|
||||
.generic = _("a DRAGON move"),
|
||||
.palette = 15,
|
||||
.zMove = MOVE_DEVASTATING_DRAKE,
|
||||
.maxMove = MOVE_MAX_WYRMWIND,
|
||||
.paletteTMHM = gItemIconPalette_DragonTMHM,
|
||||
//.enhanceItem = ITEM_DRAGON_FANG,
|
||||
//.berry = ITEM_HABAN_BERRY,
|
||||
//.gem = ITEM_DRAGON_GEM,
|
||||
//.zCrystal = ITEM_DRAGONIUM_Z,
|
||||
//.plate = ITEM_DRACO_PLATE,
|
||||
//.memory = ITEM_DRAGON_MEMORY,
|
||||
//.teraShard = ITEM_DRAGON_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_DRAGON,
|
||||
},
|
||||
[TYPE_DARK] =
|
||||
{
|
||||
.name = _("Dark"),
|
||||
.generic = _("a DARK move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_BLACK_HOLE_ECLIPSE,
|
||||
.maxMove = MOVE_MAX_DARKNESS,
|
||||
.paletteTMHM = gItemIconPalette_DarkTMHM,
|
||||
//.enhanceItem = ITEM_BLACK_GLASSES,
|
||||
//.berry = ITEM_COLBUR_BERRY,
|
||||
//.gem = ITEM_DARK_GEM,
|
||||
//.zCrystal = ITEM_DARKINIUM_Z,
|
||||
//.plate = ITEM_DREAD_PLATE,
|
||||
//.memory = ITEM_DARK_MEMORY,
|
||||
//.teraShard = ITEM_DARK_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_DARK,
|
||||
},
|
||||
[TYPE_FAIRY] =
|
||||
{
|
||||
.name = _("Fairy"),
|
||||
.generic = _("a FAIRY move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_TWINKLE_TACKLE,
|
||||
.maxMove = MOVE_MAX_STARFALL,
|
||||
.paletteTMHM = gItemIconPalette_FairyTMHM,
|
||||
//.enhanceItem = ITEM_FAIRY_FEATHER,
|
||||
//.berry = ITEM_ROSELI_BERRY,
|
||||
//.gem = ITEM_FAIRY_GEM,
|
||||
//.zCrystal = ITEM_FAIRIUM_Z,
|
||||
//.plate = ITEM_PIXIE_PLATE,
|
||||
//.memory = ITEM_FAIRY_MEMORY,
|
||||
//.teraShard = ITEM_FAIRY_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_FAIRY,
|
||||
},
|
||||
[TYPE_STELLAR] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_TYPE_NAME("Stellr", "Stellar"),
|
||||
.generic = _("a STELLAR move"),
|
||||
.palette = 15,
|
||||
.zMove = MOVE_BREAKNECK_BLITZ,
|
||||
.maxMove = MOVE_MAX_STRIKE,
|
||||
.paletteTMHM = gItemIconPalette_NormalTMHM, // failsafe
|
||||
// .teraShard = ITEM_STELLAR_TERA_SHARD,
|
||||
},
|
||||
};
|
||||
#include "data/types_info.h"
|
||||
|
||||
// extra args are money and ball
|
||||
#define TRAINER_CLASS(trainerClass, trainerName, ...) \
|
||||
@ -3446,6 +3119,7 @@ static void BattleStartClearSetData(void)
|
||||
|
||||
gBattleStruct->swapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
|
||||
gSelectedMonPartyId = PARTY_SIZE; // Revival Blessing
|
||||
gCategoryIconSpriteId = 0xFF;
|
||||
}
|
||||
|
||||
void SwitchInClearSetData(u32 battler)
|
||||
@ -3746,6 +3420,9 @@ const u8* FaintClearSetData(u32 battler)
|
||||
gBattleStruct->zmove.active = FALSE;
|
||||
gBattleStruct->zmove.toBeUsed[battler] = MOVE_NONE;
|
||||
gBattleStruct->zmove.effect = EFFECT_HIT;
|
||||
// Clear Dynamax data
|
||||
UndoDynamax(battler);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -4469,7 +4146,10 @@ static void HandleTurnActionSelectionState(void)
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart())
|
||||
&& (BattlerHasAi(battler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE)))
|
||||
{
|
||||
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, FALSE);
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_RISKY) // Risky AI switches aggressively even mid battle
|
||||
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, TRUE);
|
||||
else
|
||||
AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, FALSE);
|
||||
gBattleStruct->aiMoveOrAction[battler] = ComputeBattleAiScores(battler);
|
||||
}
|
||||
// fallthrough
|
||||
@ -5122,7 +4802,7 @@ s8 GetMovePriority(u32 battler, u16 move)
|
||||
gProtectStructs[battler].pranksterElevated = 1;
|
||||
priority++;
|
||||
}
|
||||
else if (gMovesInfo[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler))
|
||||
else if (gMovesInfo[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler) && !IsDynamaxed(battler) && !(gBattleStruct->dynamax.toDynamax & gBitTable[battler]))
|
||||
{
|
||||
priority++;
|
||||
}
|
||||
@ -6001,9 +5681,59 @@ void RunBattleScriptCommands(void)
|
||||
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
|
||||
}
|
||||
|
||||
bool32 TrySetAteType(u32 move, u32 battlerAtk, u32 attackerAbility)
|
||||
{
|
||||
u32 ateType;
|
||||
|
||||
switch (gMovesInfo[move].effect)
|
||||
{
|
||||
case EFFECT_TERA_BLAST:
|
||||
if (IsTerastallized(battlerAtk))
|
||||
return FALSE;
|
||||
break;
|
||||
case EFFECT_TERA_STARSTORM:
|
||||
if (gBattleMons[battlerAtk].species == SPECIES_TERAPAGOS_STELLAR)
|
||||
return FALSE;
|
||||
break;
|
||||
case EFFECT_HIDDEN_POWER:
|
||||
case EFFECT_WEATHER_BALL:
|
||||
case EFFECT_CHANGE_TYPE_ON_ITEM:
|
||||
case EFFECT_NATURAL_GIFT:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ateType = TYPE_NONE;
|
||||
switch (attackerAbility)
|
||||
{
|
||||
case ABILITY_PIXILATE:
|
||||
ateType = TYPE_FAIRY;
|
||||
break;
|
||||
case ABILITY_REFRIGERATE:
|
||||
ateType = TYPE_ICE;
|
||||
break;
|
||||
case ABILITY_AERILATE:
|
||||
ateType = TYPE_FLYING;
|
||||
break;
|
||||
case ABILITY_GALVANIZE:
|
||||
ateType = TYPE_ELECTRIC;
|
||||
break;
|
||||
default:
|
||||
ateType = TYPE_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ateType != TYPE_NONE)
|
||||
{
|
||||
gBattleStruct->dynamicMoveType = ateType | F_DYNAMIC_TYPE_SET;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk)
|
||||
{
|
||||
u32 moveType, ateType, attackerAbility;
|
||||
u32 moveType, attackerAbility;
|
||||
u16 holdEffect = GetBattlerHoldEffect(battlerAtk, TRUE);
|
||||
|
||||
if (move == MOVE_STRUGGLE)
|
||||
@ -6038,9 +5768,9 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk)
|
||||
| ((gBattleMons[battlerAtk].spAttackIV & 1) << 4)
|
||||
| ((gBattleMons[battlerAtk].spDefenseIV & 1) << 5);
|
||||
|
||||
// Subtract 4 instead of 1 below because 3 types are excluded (TYPE_NORMAL and TYPE_MYSTERY and TYPE_FAIRY)
|
||||
// The final + 1 skips past Normal, and the following conditional skips TYPE_MYSTERY
|
||||
gBattleStruct->dynamicMoveType = ((NUMBER_OF_MON_TYPES - 4) * typeBits) / 63 + 1;
|
||||
// Subtract 6 instead of 1 below because 5 types are excluded (TYPE_NONE, TYPE_NORMAL, TYPE_MYSTERY, TYPE_FAIRY and TYPE_STELLAR)
|
||||
// The final + 2 skips past TYPE_NONE and Normal.
|
||||
gBattleStruct->dynamicMoveType = ((NUMBER_OF_MON_TYPES - 6) * typeBits) / 63 + 2;
|
||||
if (gBattleStruct->dynamicMoveType >= TYPE_MYSTERY)
|
||||
gBattleStruct->dynamicMoveType++;
|
||||
gBattleStruct->dynamicMoveType |= F_DYNAMIC_TYPE_IGNORE_PHYSICALITY | F_DYNAMIC_TYPE_SET;
|
||||
@ -6105,29 +5835,15 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk)
|
||||
}
|
||||
|
||||
attackerAbility = GetBattlerAbility(battlerAtk);
|
||||
|
||||
if (gMovesInfo[move].type == TYPE_NORMAL
|
||||
&& gMovesInfo[move].effect != EFFECT_HIDDEN_POWER
|
||||
&& gMovesInfo[move].effect != EFFECT_WEATHER_BALL
|
||||
&& gMovesInfo[move].effect != EFFECT_CHANGE_TYPE_ON_ITEM
|
||||
&& gMovesInfo[move].effect != EFFECT_NATURAL_GIFT
|
||||
&& !(gMovesInfo[move].effect == EFFECT_TERA_BLAST && IsTerastallized(battlerAtk))
|
||||
&& !(gMovesInfo[move].effect == EFFECT_TERA_STARSTORM && gBattleMons[battlerAtk].species == SPECIES_TERAPAGOS_STELLAR)
|
||||
&& ((attackerAbility == ABILITY_PIXILATE && (ateType = TYPE_FAIRY))
|
||||
|| (attackerAbility == ABILITY_REFRIGERATE && (ateType = TYPE_ICE))
|
||||
|| (attackerAbility == ABILITY_AERILATE && (ateType = TYPE_FLYING))
|
||||
|| ((attackerAbility == ABILITY_GALVANIZE) && (ateType = TYPE_ELECTRIC))
|
||||
)
|
||||
)
|
||||
if (gMovesInfo[move].type == TYPE_NORMAL && TrySetAteType(move, battlerAtk, attackerAbility))
|
||||
{
|
||||
gBattleStruct->dynamicMoveType = ateType | F_DYNAMIC_TYPE_SET;
|
||||
if (!IsDynamaxed(battlerAtk))
|
||||
gBattleStruct->ateBoost[battlerAtk] = 1;
|
||||
}
|
||||
else if (gMovesInfo[move].type != TYPE_NORMAL
|
||||
&& gMovesInfo[move].effect != EFFECT_HIDDEN_POWER
|
||||
&& gMovesInfo[move].effect != EFFECT_WEATHER_BALL
|
||||
&& attackerAbility == ABILITY_NORMALIZE)
|
||||
&& gMovesInfo[move].effect != EFFECT_HIDDEN_POWER
|
||||
&& gMovesInfo[move].effect != EFFECT_WEATHER_BALL
|
||||
&& attackerAbility == ABILITY_NORMALIZE)
|
||||
{
|
||||
gBattleStruct->dynamicMoveType = TYPE_NORMAL | F_DYNAMIC_TYPE_SET;
|
||||
if (!IsDynamaxed(battlerAtk))
|
||||
|
||||
@ -91,7 +91,7 @@ static const u8 sText_CantEscape2[] = _("Can't escape!\p");
|
||||
static const u8 sText_AttackerCantEscape[] = _("{B_ATK_NAME_WITH_PREFIX} can't escape!");
|
||||
static const u8 sText_HitXTimes[] = _("Hit {B_BUFF1} time(s)!");
|
||||
static const u8 sText_PkmnFellAsleep[] = _("{B_EFF_NAME_WITH_PREFIX}\nfell asleep!");
|
||||
static const u8 sText_PkmnMadeSleep[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nmade {B_EFF_NAME_WITH_PREFIX} sleep!");
|
||||
static const u8 sText_PkmnMadeSleep[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nmade {B_EFF_NAME_WITH_PREFIX} sleep!");
|
||||
static const u8 sText_PkmnAlreadyAsleep[] = _("{B_DEF_NAME_WITH_PREFIX} is\nalready asleep!");
|
||||
static const u8 sText_PkmnAlreadyAsleep2[] = _("{B_ATK_NAME_WITH_PREFIX} is\nalready asleep!");
|
||||
static const u8 sText_PkmnWasntAffected[] = _("{B_DEF_NAME_WITH_PREFIX}\nwasn't affected!");
|
||||
@ -103,12 +103,12 @@ static const u8 sText_PkmnBadlyPoisoned[] = _("{B_EFF_NAME_WITH_PREFIX} is badly
|
||||
static const u8 sText_PkmnEnergyDrained[] = _("{B_DEF_NAME_WITH_PREFIX} had its\nenergy drained!");
|
||||
static const u8 sText_PkmnWasBurned[] = _("{B_EFF_NAME_WITH_PREFIX} was burned!");
|
||||
static const u8 sText_PkmnGotFrostbite[] = _("{B_EFF_NAME_WITH_PREFIX} got frostbite!");
|
||||
static const u8 sText_PkmnBurnedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nburned {B_EFF_NAME_WITH_PREFIX}!");
|
||||
static const u8 sText_PkmnBurnedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nburned {B_EFF_NAME_WITH_PREFIX}!");
|
||||
static const u8 sText_PkmnHurtByBurn[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt\nby its burn!");
|
||||
static const u8 sText_PkmnHurtByFrostbite[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt\nby its frostbite!");
|
||||
static const u8 sText_PkmnAlreadyHasBurn[] = _("{B_DEF_NAME_WITH_PREFIX} already\nhas a burn.");
|
||||
static const u8 sText_PkmnWasFrozen[] = _("{B_EFF_NAME_WITH_PREFIX} was\nfrozen solid!");
|
||||
static const u8 sText_PkmnFrozenBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nfroze {B_EFF_NAME_WITH_PREFIX} solid!");
|
||||
static const u8 sText_PkmnFrozenBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nfroze {B_EFF_NAME_WITH_PREFIX} solid!");
|
||||
static const u8 sText_PkmnIsFrozen[] = _("{B_ATK_NAME_WITH_PREFIX} is\nfrozen solid!");
|
||||
static const u8 sText_PkmnWasDefrosted[] = _("{B_DEF_NAME_WITH_PREFIX} was\ndefrosted!");
|
||||
static const u8 sText_PkmnWasDefrosted2[] = _("{B_ATK_NAME_WITH_PREFIX} was\ndefrosted!");
|
||||
@ -117,7 +117,7 @@ static const u8 sText_PkmnFrostbiteHealed[] = _("{B_DEF_NAME_WITH_PREFIX}'s\nfro
|
||||
static const u8 sText_PkmnFrostbiteHealed2[] = _("{B_ATK_NAME_WITH_PREFIX}'s\nfrostbite was healed!");
|
||||
static const u8 sText_PkmnFrostbiteHealedBy[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE}\nhealed its frostbite!");
|
||||
static const u8 sText_PkmnWasParalyzed[] = _("{B_EFF_NAME_WITH_PREFIX} is paralyzed!\nIt may be unable to move!");
|
||||
static const u8 sText_PkmnWasParalyzedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nparalyzed {B_EFF_NAME_WITH_PREFIX}!\lIt may be unable to move!");
|
||||
static const u8 sText_PkmnWasParalyzedBy[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1}\nparalyzed {B_EFF_NAME_WITH_PREFIX}!\lIt may be unable to move!");
|
||||
static const u8 sText_PkmnIsParalyzed[] = _("{B_ATK_NAME_WITH_PREFIX} is paralyzed!\nIt can't move!");
|
||||
static const u8 sText_PkmnIsAlreadyParalyzed[] = _("{B_DEF_NAME_WITH_PREFIX} is\nalready paralyzed!");
|
||||
static const u8 sText_PkmnHealedParalysis[] = _("{B_DEF_NAME_WITH_PREFIX} was\nhealed of paralysis!");
|
||||
@ -2492,6 +2492,18 @@ static const struct BattleWindowText sTextOnWindowsInfo_Normal[] =
|
||||
.fgColor = 1,
|
||||
.shadowColor = 6,
|
||||
},
|
||||
[B_WIN_MOVE_DESCRIPTION] = {
|
||||
.fillValue = PIXEL_FILL(0xE),
|
||||
.fontId = FONT_NARROW,
|
||||
.x = 0,
|
||||
.y = 1,
|
||||
.letterSpacing = 0,
|
||||
.lineSpacing = 0,
|
||||
.speed = 0,
|
||||
.fgColor = TEXT_DYNAMIC_COLOR_4,
|
||||
.bgColor = TEXT_DYNAMIC_COLOR_5,
|
||||
.shadowColor = TEXT_DYNAMIC_COLOR_6,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct BattleWindowText sTextOnWindowsInfo_Arena[] =
|
||||
@ -2725,6 +2737,18 @@ static const struct BattleWindowText sTextOnWindowsInfo_Arena[] =
|
||||
.bgColor = 1,
|
||||
.shadowColor = 3,
|
||||
},
|
||||
[B_WIN_MOVE_DESCRIPTION] = {
|
||||
.fillValue = PIXEL_FILL(0xE),
|
||||
.fontId = FONT_NARROW,
|
||||
.x = 0,
|
||||
.y = 1,
|
||||
.letterSpacing = 0,
|
||||
.lineSpacing = 0,
|
||||
.speed = 0,
|
||||
.fgColor = TEXT_DYNAMIC_COLOR_4,
|
||||
.bgColor = TEXT_DYNAMIC_COLOR_5,
|
||||
.shadowColor = TEXT_DYNAMIC_COLOR_6,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct BattleWindowText *const sBattleTextOnWindowsInfo[] =
|
||||
|
||||
@ -337,6 +337,8 @@ static bool8 CanBurnHitThaw(u16 move);
|
||||
static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent);
|
||||
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove);
|
||||
static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move);
|
||||
static void SaveBattlerAttacker(u32 battler);
|
||||
static void SaveBattlerTarget(u32 battler);
|
||||
|
||||
static void Cmd_attackcanceler(void);
|
||||
static void Cmd_accuracycheck(void);
|
||||
@ -6168,7 +6170,8 @@ static void Cmd_moveend(void)
|
||||
&& CanBattlerSwitch(gBattlerAttacker))
|
||||
{
|
||||
gLastUsedItem = gBattleMons[battler].item;
|
||||
gBattleStruct->savedBattlerTarget = gBattleScripting.battler = battler; // Battler with red card
|
||||
SaveBattlerTarget(battler); // save battler with red card
|
||||
gBattleScripting.battler = battler;
|
||||
gEffectBattler = gBattlerAttacker;
|
||||
if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE)
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
|
||||
@ -6228,8 +6231,19 @@ static void Cmd_moveend(void)
|
||||
case MOVEEND_DANCER: // Special case because it's so annoying
|
||||
if (gMovesInfo[gCurrentMove].danceMove)
|
||||
{
|
||||
u8 battler, nextDancer = 0;
|
||||
u32 battler, nextDancer = 0;
|
||||
bool32 turnOnHitmarker = FALSE;
|
||||
|
||||
for (battler = 0; battler < MAX_BATTLERS_COUNT; battler++)
|
||||
{
|
||||
if (gSpecialStatuses[battler].dancerUsedMove)
|
||||
{
|
||||
// in case a battler fails to act on a Dancer-called move
|
||||
turnOnHitmarker = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(gBattleStruct->lastMoveFailed & gBitTable[gBattlerAttacker]
|
||||
|| (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove
|
||||
&& gBattleStruct->bouncedMoveIsUsed)))
|
||||
@ -6245,6 +6259,8 @@ static void Cmd_moveend(void)
|
||||
{
|
||||
if (GetBattlerAbility(battler) == ABILITY_DANCER && !gSpecialStatuses[battler].dancerUsedMove)
|
||||
{
|
||||
if (turnOnHitmarker)
|
||||
gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED;
|
||||
if (!nextDancer || (gBattleMons[battler].speed < gBattleMons[nextDancer & 0x3].speed))
|
||||
nextDancer = battler | 0x4;
|
||||
}
|
||||
@ -6325,6 +6341,25 @@ static void Cmd_moveend(void)
|
||||
&& (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) // And it is unusable
|
||||
&& (gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) != STATUS2_LOCK_CONFUSE_TURN(1)) // And won't end this turn
|
||||
CancelMultiTurnMoves(gBattlerAttacker); // Cancel it
|
||||
|
||||
|
||||
|
||||
if (gBattleStruct->savedAttackerCount > 0)
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!");
|
||||
// #endif
|
||||
}
|
||||
if (gBattleStruct->savedTargetCount > 0)
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
// #endif
|
||||
}
|
||||
|
||||
gBattleStruct->targetsDone[gBattlerAttacker] = 0;
|
||||
gProtectStructs[gBattlerAttacker].targetAffected = FALSE;
|
||||
@ -9379,18 +9414,6 @@ static void Cmd_various(void)
|
||||
AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
case VARIOUS_SAVE_TARGET:
|
||||
{
|
||||
VARIOUS_ARGS();
|
||||
gBattleStruct->savedBattlerTarget = gBattlerTarget;
|
||||
break;
|
||||
}
|
||||
case VARIOUS_RESTORE_TARGET:
|
||||
{
|
||||
VARIOUS_ARGS();
|
||||
gBattlerTarget = gBattleStruct->savedBattlerTarget;
|
||||
break;
|
||||
}
|
||||
case VARIOUS_INSTANT_HP_DROP:
|
||||
{
|
||||
VARIOUS_ARGS();
|
||||
@ -15655,6 +15678,75 @@ static void Cmd_callnative(void)
|
||||
}
|
||||
|
||||
// Callnative Funcs
|
||||
|
||||
static void SaveBattlerTarget(u32 battler)
|
||||
{
|
||||
if (gBattleStruct->savedTargetCount < NELEMS(gBattleStruct->savedBattlerTarget))
|
||||
gBattleStruct->savedBattlerTarget[gBattleStruct->savedTargetCount++] = battler;
|
||||
else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "Attempting to exceed savedBattlerTarget array size!");
|
||||
}
|
||||
|
||||
static void SaveBattlerAttacker(u32 battler)
|
||||
{
|
||||
if (gBattleStruct->savedAttackerCount < NELEMS(gBattleStruct->savedBattlerAttacker))
|
||||
gBattleStruct->savedBattlerAttacker[gBattleStruct->savedAttackerCount++] = battler;
|
||||
else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "Attempting to exceed savedBattlerAttacker array size!");
|
||||
}
|
||||
|
||||
void BS_SaveTarget(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
SaveBattlerTarget(gBattlerTarget);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_RestoreTarget(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
if (gBattleStruct->savedTargetCount > 0)
|
||||
{
|
||||
gBattleStruct->savedTargetCount--;
|
||||
gBattlerTarget = gBattleStruct->savedBattlerTarget[gBattleStruct->savedTargetCount];
|
||||
}
|
||||
else
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "BS_RestoreTarget attempting to restore an empty target!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "BS_RestoreTarget attempting to restore an empty target!");
|
||||
// #endif
|
||||
}
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_SaveAttacker(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
SaveBattlerAttacker(gBattlerAttacker);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_RestoreAttacker(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
if (gBattleStruct->savedAttackerCount > 0)
|
||||
{
|
||||
gBattleStruct->savedAttackerCount--;
|
||||
gBattlerAttacker = gBattleStruct->savedBattlerAttacker[gBattleStruct->savedAttackerCount];
|
||||
}
|
||||
else
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "BS_RestoreAttacker attempting to restore an empty attacker!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "BS_RestoreAttacker attempting to restore an empty attacker!");
|
||||
// #endif
|
||||
}
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_CalcMetalBurstDmg(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
|
||||
@ -169,33 +169,9 @@ uq4_12_t GetTeraMultiplier(u32 battler, u32 type)
|
||||
}
|
||||
}
|
||||
|
||||
// Most values pulled from the Tera type icon palette.
|
||||
const u16 sTeraTypeRGBValues[NUMBER_OF_MON_TYPES] = {
|
||||
[TYPE_NORMAL] = RGB_WHITE, // custom
|
||||
[TYPE_FIGHTING] = RGB(26, 8, 14),
|
||||
[TYPE_FLYING] = RGB(31, 26, 7),
|
||||
[TYPE_POISON] = RGB(26, 10, 25), // custom
|
||||
[TYPE_GROUND] = RGB(25, 23, 18),
|
||||
[TYPE_ROCK] = RGB(18, 16, 8), // custom
|
||||
[TYPE_BUG] = RGB(18, 24, 6),
|
||||
[TYPE_GHOST] = RGB(12, 10, 16),
|
||||
[TYPE_STEEL] = RGB(19, 19, 20),
|
||||
[TYPE_MYSTERY] = RGB_WHITE,
|
||||
[TYPE_FIRE] = RGB(31, 20, 11),
|
||||
[TYPE_WATER] = RGB(10, 18, 27),
|
||||
[TYPE_GRASS] = RGB(12, 24, 11),
|
||||
[TYPE_ELECTRIC] = RGB(30, 26, 7),
|
||||
[TYPE_PSYCHIC] = RGB(31, 14, 15),
|
||||
[TYPE_ICE] = RGB(14, 26, 25),
|
||||
[TYPE_DRAGON] = RGB(10, 18, 27),
|
||||
[TYPE_DARK] = RGB(6, 5, 8),
|
||||
[TYPE_FAIRY] = RGB(31, 15, 21),
|
||||
[TYPE_STELLAR] = RGB(10, 18, 27),
|
||||
};
|
||||
|
||||
u16 GetTeraTypeRGB(u32 type)
|
||||
{
|
||||
return sTeraTypeRGBValues[type];
|
||||
return gTypesInfo[type].teraTypeRGBValue;
|
||||
}
|
||||
|
||||
// TERASTAL TRIGGER:
|
||||
@ -636,6 +612,7 @@ static const struct SpriteTemplate sSpriteTemplate_StellarIndicator =
|
||||
|
||||
static const struct SpriteSheet sTeraIndicatorSpriteSheets[NUMBER_OF_MON_TYPES + 1] =
|
||||
{
|
||||
{sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), TAG_NORMAL_INDICATOR_TILE}, // TYPE_NONE
|
||||
{sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), TAG_NORMAL_INDICATOR_TILE},
|
||||
{sFightingIndicatorGfx, sizeof(sFightingIndicatorGfx), TAG_FIGHTING_INDICATOR_TILE},
|
||||
{sFlyingIndicatorGfx, sizeof(sFlyingIndicatorGfx), TAG_FLYING_INDICATOR_TILE},
|
||||
@ -661,6 +638,7 @@ static const struct SpriteSheet sTeraIndicatorSpriteSheets[NUMBER_OF_MON_TYPES +
|
||||
|
||||
static const struct SpriteTemplate * const sTeraIndicatorSpriteTemplates[NUMBER_OF_MON_TYPES] =
|
||||
{
|
||||
[TYPE_NONE] = &sSpriteTemplate_NormalIndicator, // just in case
|
||||
[TYPE_NORMAL] = &sSpriteTemplate_NormalIndicator,
|
||||
[TYPE_FIGHTING] = &sSpriteTemplate_FightingIndicator,
|
||||
[TYPE_FLYING] = &sSpriteTemplate_FlyingIndicator,
|
||||
|
||||
@ -903,44 +903,6 @@ static const uq4_12_t sPercentToModifier[] =
|
||||
UQ_4_12(1.00), // 100
|
||||
};
|
||||
|
||||
#define X UQ_4_12
|
||||
#define ______ X(1.0) // Regular effectiveness.
|
||||
|
||||
// Type matchup updates. Attacker Defender
|
||||
#define STL_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_6 ? X(1.0) : X(0.5)) // Ghost/Dark -> Steel
|
||||
#define PSN_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(2.0)) // Bug -> Poison
|
||||
#define BUG_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(1.0) : X(2.0)) // Poison -> Bug
|
||||
#define PSY_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(2.0) : X(0.0)) // Ghost -> Psychic
|
||||
#define FIR_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(1.0)) // Ice -> Fire
|
||||
|
||||
static const uq4_12_t sTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES] =
|
||||
{// Defender -->
|
||||
// Attacker Normal Fighting Flying Poison Ground Rock Bug Ghost Steel Mystery Fire Water Grass Electric Psychic Ice Dragon Dark Fairy Stellar
|
||||
[TYPE_NORMAL] = {______, ______, ______, ______, ______, X(0.5), ______, X(0.0), X(0.5), ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______},
|
||||
[TYPE_FIGHTING] = {X(2.0), ______, X(0.5), X(0.5), ______, X(2.0), X(0.5), X(0.0), X(2.0), ______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), X(0.5), ______},
|
||||
[TYPE_FLYING] = {______, X(2.0), ______, ______, ______, X(0.5), X(2.0), ______, X(0.5), ______, ______, ______, X(2.0), X(0.5), ______, ______, ______, ______, ______, ______},
|
||||
[TYPE_POISON] = {______, ______, ______, X(0.5), X(0.5), X(0.5), BUG_RS, X(0.5), X(0.0), ______, ______, ______, X(2.0), ______, ______, ______, ______, ______, X(2.0), ______},
|
||||
[TYPE_GROUND] = {______, ______, X(0.0), X(2.0), ______, X(2.0), X(0.5), ______, X(2.0), ______, X(2.0), ______, X(0.5), X(2.0), ______, ______, ______, ______, ______, ______},
|
||||
[TYPE_ROCK] = {______, X(0.5), X(2.0), ______, X(0.5), ______, X(2.0), ______, X(0.5), ______, X(2.0), ______, ______, ______, ______, X(2.0), ______, ______, ______, ______},
|
||||
[TYPE_BUG] = {______, X(0.5), X(0.5), PSN_RS, ______, ______, ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, X(2.0), ______, ______, X(2.0), X(0.5), ______},
|
||||
[TYPE_GHOST] = {X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, PSY_RS, ______, ______, X(0.5), ______, ______},
|
||||
[TYPE_STEEL] = {______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, ______, X(2.0), ______},
|
||||
[TYPE_MYSTERY] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______},
|
||||
[TYPE_FIRE] = {______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), ______, X(0.5), X(0.5), X(2.0), ______, ______, X(2.0), X(0.5), ______, ______, ______},
|
||||
[TYPE_WATER] = {______, ______, ______, ______, X(2.0), X(2.0), ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______},
|
||||
[TYPE_GRASS] = {______, ______, X(0.5), X(0.5), X(2.0), X(2.0), X(0.5), ______, X(0.5), ______, X(0.5), X(2.0), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______},
|
||||
[TYPE_ELECTRIC] = {______, ______, X(2.0), ______, X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, X(0.5), ______, ______, ______},
|
||||
[TYPE_PSYCHIC] = {______, X(2.0), ______, X(2.0), ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, X(0.5), ______, ______, X(0.0), ______, ______},
|
||||
[TYPE_ICE] = {______, ______, X(2.0), ______, X(2.0), ______, ______, ______, X(0.5), ______, FIR_RS, X(0.5), X(2.0), ______, ______, X(0.5), X(2.0), ______, ______, ______},
|
||||
[TYPE_DRAGON] = {______, ______, ______, ______, ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, ______, ______, X(2.0), ______, X(0.0), ______},
|
||||
[TYPE_DARK] = {______, X(0.5), ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), X(0.5), ______},
|
||||
[TYPE_FAIRY] = {______, X(2.0), ______, X(0.5), ______, ______, ______, ______, X(0.5), ______, X(0.5), ______, ______, ______, ______, ______, X(2.0), X(2.0), ______, ______},
|
||||
[TYPE_STELLAR] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______},
|
||||
};
|
||||
|
||||
#undef ______
|
||||
#undef X
|
||||
|
||||
// code
|
||||
u8 GetBattlerForBattleScript(u8 caseId)
|
||||
{
|
||||
@ -4408,7 +4370,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
if (!gSpecialStatuses[battler].switchInAbilityDone)
|
||||
{
|
||||
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
|
||||
gBattlerAttacker = battler;
|
||||
gBattleScripting.battler = battler;
|
||||
BattleScriptPushCursorAndCallback(BattleScript_FriskActivates); // Try activate
|
||||
effect++;
|
||||
}
|
||||
@ -4970,10 +4932,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
BattleScriptPushCursorAndCallback(BattleScript_BadDreamsActivates);
|
||||
effect++;
|
||||
break;
|
||||
SOLAR_POWER_HP_DROP:
|
||||
case ABILITY_SOLAR_POWER:
|
||||
if (IsBattlerWeatherAffected(battler, B_WEATHER_SUN))
|
||||
{
|
||||
SOLAR_POWER_HP_DROP:
|
||||
BattleScriptPushCursorAndCallback(BattleScript_SolarPowerActivates);
|
||||
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8;
|
||||
if (gBattleMoveDamage == 0)
|
||||
@ -5045,31 +5007,70 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
case ABILITYEFFECT_WOULD_BLOCK:
|
||||
{
|
||||
u16 moveTarget = GetBattlerMoveTargetType(battler, move);
|
||||
u16 battlerAbility = GetBattlerAbility(battler);
|
||||
u16 targetAbility = GetBattlerAbility(gBattlerTarget);
|
||||
const u8 * battleScriptBlocksMove = NULL;
|
||||
|
||||
if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gMovesInfo[move].soundMove && !(moveTarget & MOVE_TARGET_USER))
|
||||
|| (gLastUsedAbility == ABILITY_BULLETPROOF && gMovesInfo[move].ballisticMove))
|
||||
switch (gLastUsedAbility)
|
||||
{
|
||||
case ABILITY_SOUNDPROOF:
|
||||
if (gMovesInfo[move].soundMove && !(moveTarget & MOVE_TARGET_USER))
|
||||
effect = 1;
|
||||
break;
|
||||
case ABILITY_BULLETPROOF:
|
||||
if (gMovesInfo[move].ballisticMove)
|
||||
effect = 1;
|
||||
break;
|
||||
case ABILITY_DAZZLING:
|
||||
case ABILITY_QUEENLY_MAJESTY:
|
||||
case ABILITY_ARMOR_TAIL:
|
||||
if (GetChosenMovePriority(gBattlerAttacker) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
|
||||
effect = 2;
|
||||
break;
|
||||
case ABILITY_GOOD_AS_GOLD:
|
||||
if (IS_MOVE_STATUS(gCurrentMove)
|
||||
&& !(moveTarget & MOVE_TARGET_USER)
|
||||
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
|
||||
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
|
||||
effect = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!effect)
|
||||
{
|
||||
switch (GetBattlerAbility(BATTLE_PARTNER(battler)))
|
||||
{
|
||||
case ABILITY_DAZZLING:
|
||||
case ABILITY_QUEENLY_MAJESTY:
|
||||
case ABILITY_ARMOR_TAIL:
|
||||
if (GetChosenMovePriority(gBattlerAttacker) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
|
||||
effect = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (effect == 1)
|
||||
{
|
||||
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
battleScriptBlocksMove = BattleScript_SoundproofProtected;
|
||||
effect = 1;
|
||||
}
|
||||
else if ((gLastUsedAbility == ABILITY_DAZZLING || gLastUsedAbility == ABILITY_QUEENLY_MAJESTY || gLastUsedAbility == ABILITY_ARMOR_TAIL || IsBattlerAlive(battler ^= BIT_FLANK))
|
||||
&& (battlerAbility == ABILITY_DAZZLING || battlerAbility == ABILITY_QUEENLY_MAJESTY || battlerAbility == ABILITY_ARMOR_TAIL)
|
||||
&& GetChosenMovePriority(gBattlerAttacker) > 0
|
||||
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler))
|
||||
else if (effect == 2 || effect == 4)
|
||||
{
|
||||
if (effect == 4)
|
||||
gBattleScripting.battler = BATTLE_PARTNER(battler);
|
||||
else
|
||||
gBattleScripting.battler = battler;
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
|
||||
gHitMarker |= HITMARKER_NO_PPDEDUCT;
|
||||
battleScriptBlocksMove = BattleScript_DazzlingProtected;
|
||||
effect = 1;
|
||||
}
|
||||
else if (effect == 3)
|
||||
{
|
||||
battleScriptBlocksMove = BattleScript_GoodAsGoldActivates;
|
||||
}
|
||||
else if (GetChosenMovePriority(gBattlerAttacker) > 0
|
||||
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
|
||||
&& !(IS_MOVE_STATUS(move) && (targetAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
|
||||
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
|
||||
&& !(IS_MOVE_STATUS(move) && (gLastUsedAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
|
||||
{
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)))
|
||||
CancelMultiTurnMoves(gBattlerAttacker); // Don't cancel moves that can hit two targets bc one target might not be protected
|
||||
@ -5077,15 +5078,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
battleScriptBlocksMove = BattleScript_DarkTypePreventsPrankster;
|
||||
effect = 1;
|
||||
}
|
||||
else if (GetBattlerAbility(gBattlerTarget) == ABILITY_GOOD_AS_GOLD
|
||||
&& IS_MOVE_STATUS(gCurrentMove)
|
||||
&& !(moveTarget & MOVE_TARGET_USER)
|
||||
&& !(moveTarget & MOVE_TARGET_OPPONENTS_FIELD)
|
||||
&& !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
|
||||
{
|
||||
battleScriptBlocksMove = BattleScript_GoodAsGoldActivates;
|
||||
effect = 1;
|
||||
}
|
||||
if (caseID == ABILITYEFFECT_WOULD_BLOCK)
|
||||
{
|
||||
if (effect && gLastUsedAbility != 0xFFFF)
|
||||
@ -5562,6 +5554,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& RandomWeighted(RNG_STATIC, 2, 1))
|
||||
{
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS;
|
||||
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect;
|
||||
gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT;
|
||||
@ -5579,6 +5572,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& RandomWeighted(RNG_FLAME_BODY, 2, 1))
|
||||
{
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN;
|
||||
PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect;
|
||||
gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT;
|
||||
@ -5851,6 +5845,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
if (IsBattlerAlive(battler)
|
||||
&& (gMovesInfo[gCurrentMove].danceMove)
|
||||
&& !gSpecialStatuses[battler].dancerUsedMove
|
||||
&& (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED)
|
||||
&& gBattlerAttacker != battler)
|
||||
{
|
||||
// Set bit and save Dancer mon's original target
|
||||
@ -9994,7 +9989,7 @@ static inline s32 DoMoveDamageCalcVars(u32 move, u32 battlerAtk, u32 battlerDef,
|
||||
|
||||
if (randomFactor)
|
||||
{
|
||||
dmg *= 100 - RandomUniform(RNG_DAMAGE_MODIFIER, 0, 15);
|
||||
dmg *= DMG_ROLL_PERCENT_HI - RandomUniform(RNG_DAMAGE_MODIFIER, 0, DMG_ROLL_PERCENT_HI - DMG_ROLL_PERCENT_LO);
|
||||
dmg /= 100;
|
||||
}
|
||||
|
||||
@ -10055,7 +10050,7 @@ static inline s32 DoFutureSightAttackDamageCalcVars(u32 move, u32 battlerAtk, u3
|
||||
|
||||
if (randomFactor)
|
||||
{
|
||||
dmg *= 100 - RandomUniform(RNG_DAMAGE_MODIFIER, 0, 15);
|
||||
dmg *= DMG_ROLL_PERCENT_HI - RandomUniform(RNG_DAMAGE_MODIFIER, 0, DMG_ROLL_PERCENT_HI - DMG_ROLL_PERCENT_LO);
|
||||
dmg /= 100;
|
||||
}
|
||||
|
||||
@ -10366,8 +10361,8 @@ uq4_12_t GetTypeEffectiveness(struct Pokemon *mon, u8 moveType)
|
||||
uq4_12_t GetTypeModifier(u32 atkType, u32 defType)
|
||||
{
|
||||
if (B_FLAG_INVERSE_BATTLE != 0 && FlagGet(B_FLAG_INVERSE_BATTLE))
|
||||
return GetInverseTypeMultiplier(sTypeEffectivenessTable[atkType][defType]);
|
||||
return sTypeEffectivenessTable[atkType][defType];
|
||||
return GetInverseTypeMultiplier(gTypeEffectivenessTable[atkType][defType]);
|
||||
return gTypeEffectivenessTable[atkType][defType];
|
||||
}
|
||||
|
||||
s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp)
|
||||
@ -10911,10 +10906,8 @@ u8 GetBattleMoveCategory(u32 moveId)
|
||||
|
||||
if (IS_MOVE_STATUS(moveId))
|
||||
return DAMAGE_CATEGORY_STATUS;
|
||||
else if (gMovesInfo[moveId].type < TYPE_MYSTERY)
|
||||
return DAMAGE_CATEGORY_PHYSICAL;
|
||||
else
|
||||
return DAMAGE_CATEGORY_SPECIAL;
|
||||
return gTypesInfo[gMovesInfo[moveId].type].damageCategory;
|
||||
}
|
||||
|
||||
static bool32 TryRemoveScreens(u32 battler)
|
||||
|
||||
@ -1602,6 +1602,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
|
||||
.name = _("Disguise"),
|
||||
.description = COMPOUND_STRING("Decoy protects it once."),
|
||||
.aiRating = 8,
|
||||
.breakable = TRUE,
|
||||
.cantBeCopied = TRUE,
|
||||
.cantBeSwapped = TRUE,
|
||||
.cantBeTraced = TRUE,
|
||||
|
||||
@ -21934,10 +21934,10 @@ const u32 gObjectEventPic_Substitute[] = INCBIN_COMP("graphics/pokemon/question_
|
||||
#endif //P_FAMILY_IRON_CROWN
|
||||
|
||||
#if P_FAMILY_TERAPAGOS
|
||||
// const u32 gMonFrontPic_TerapagosNormal[] = INCBIN_U32("graphics/pokemon/terapagos/front.4bpp.lz");
|
||||
// const u32 gMonPalette_TerapagosNormal[] = INCBIN_U32("graphics/pokemon/terapagos/normal.gbapal.lz");
|
||||
// const u32 gMonBackPic_TerapagosNormal[] = INCBIN_U32("graphics/pokemon/terapagos/back.4bpp.lz");
|
||||
// const u32 gMonShinyPalette_TerapagosNormal[] = INCBIN_U32("graphics/pokemon/terapagos/shiny.gbapal.lz");
|
||||
const u32 gMonFrontPic_TerapagosNormal[] = INCBIN_U32("graphics/pokemon/terapagos/anim_front.4bpp.lz");
|
||||
const u32 gMonPalette_TerapagosNormal[] = INCBIN_U32("graphics/pokemon/terapagos/normal.gbapal.lz");
|
||||
const u32 gMonBackPic_TerapagosNormal[] = INCBIN_U32("graphics/pokemon/terapagos/back.4bpp.lz");
|
||||
const u32 gMonShinyPalette_TerapagosNormal[] = INCBIN_U32("graphics/pokemon/terapagos/shiny.gbapal.lz");
|
||||
const u8 gMonIcon_TerapagosNormal[] = INCBIN_U8("graphics/pokemon/terapagos/icon.4bpp");
|
||||
#if P_FOOTPRINTS
|
||||
const u8 gMonFootprint_TerapagosNormal[] = INCBIN_U8("graphics/pokemon/terapagos/footprint.1bpp");
|
||||
@ -21950,10 +21950,10 @@ const u32 gObjectEventPic_Substitute[] = INCBIN_COMP("graphics/pokemon/question_
|
||||
#endif //OW_FOLLOWERS_SHARE_PALETTE
|
||||
#endif //OW_FOLLOWERS_ENABLED
|
||||
|
||||
// const u32 gMonFrontPic_TerapagosTerastal[] = INCBIN_U32("graphics/pokemon/terapagos/terastal/front.4bpp.lz");
|
||||
// const u32 gMonPalette_TerapagosTerastal[] = INCBIN_U32("graphics/pokemon/terapagos/terastal/normal.gbapal.lz");
|
||||
// const u32 gMonBackPic_TerapagosTerastal[] = INCBIN_U32("graphics/pokemon/terapagos/terastal/back.4bpp.lz");
|
||||
// const u32 gMonShinyPalette_TerapagosTerastal[] = INCBIN_U32("graphics/pokemon/terapagos/terastal/shiny.gbapal.lz");
|
||||
const u32 gMonFrontPic_TerapagosTerastal[] = INCBIN_U32("graphics/pokemon/terapagos/terastal/anim_front.4bpp.lz");
|
||||
const u32 gMonPalette_TerapagosTerastal[] = INCBIN_U32("graphics/pokemon/terapagos/terastal/normal.gbapal.lz");
|
||||
const u32 gMonBackPic_TerapagosTerastal[] = INCBIN_U32("graphics/pokemon/terapagos/terastal/back.4bpp.lz");
|
||||
const u32 gMonShinyPalette_TerapagosTerastal[] = INCBIN_U32("graphics/pokemon/terapagos/terastal/shiny.gbapal.lz");
|
||||
const u8 gMonIcon_TerapagosTerastal[] = INCBIN_U8("graphics/pokemon/terapagos/terastal/icon.4bpp");
|
||||
#if P_FOOTPRINTS
|
||||
const u8 gMonFootprint_TerapagosTerastal[] = INCBIN_U8("graphics/pokemon/terapagos/terastal/footprint.1bpp");
|
||||
|
||||
@ -0,0 +1 @@
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -6619,17 +6619,18 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
|
||||
.pokemonOffset = 0,
|
||||
.trainerScale = 365,
|
||||
.trainerOffset = 7,
|
||||
//.frontPic = gMonFrontPic_TerapagosNormal,
|
||||
//.frontPicSize = MON_COORDS_SIZE(64, 64),
|
||||
.frontPic = gMonFrontPic_TerapagosNormal,
|
||||
.frontPicSize = MON_COORDS_SIZE(64, 64),
|
||||
.frontPicYOffset = 0,
|
||||
.frontAnimFrames = sAnims_TerapagosNormal,
|
||||
//.frontAnimId = ANIM_V_SQUISH_AND_BOUNCE,
|
||||
//.backPic = gMonBackPic_TerapagosNormal,
|
||||
//.backPicSize = MON_COORDS_SIZE(64, 64),
|
||||
.frontAnimId = ANIM_V_SQUISH_AND_BOUNCE,
|
||||
.enemyMonElevation = 1,
|
||||
.backPic = gMonBackPic_TerapagosNormal,
|
||||
.backPicSize = MON_COORDS_SIZE(64, 64),
|
||||
.backPicYOffset = 0,
|
||||
//.backAnimId = BACK_ANIM_NONE,
|
||||
//.palette = gMonPalette_TerapagosNormal,
|
||||
//.shinyPalette = gMonShinyPalette_TerapagosNormal,
|
||||
.backAnimId = BACK_ANIM_NONE,
|
||||
.palette = gMonPalette_TerapagosNormal,
|
||||
.shinyPalette = gMonShinyPalette_TerapagosNormal,
|
||||
.iconSprite = gMonIcon_TerapagosNormal,
|
||||
.iconPalIndex = 0,
|
||||
FOOTPRINT(TerapagosNormal)
|
||||
@ -6676,17 +6677,18 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
|
||||
.pokemonOffset = 0,
|
||||
.trainerScale = 365,
|
||||
.trainerOffset = 7,
|
||||
//.frontPic = gMonFrontPic_TerapagosTerastal,
|
||||
//.frontPicSize = MON_COORDS_SIZE(64, 64),
|
||||
.frontPicYOffset = 0,
|
||||
.frontPic = gMonFrontPic_TerapagosTerastal,
|
||||
.frontPicSize = MON_COORDS_SIZE(64, 64),
|
||||
.frontPicYOffset = 8,
|
||||
.frontAnimFrames = sAnims_TerapagosTerastal,
|
||||
//.frontAnimId = ANIM_V_SQUISH_AND_BOUNCE,
|
||||
//.backPic = gMonBackPic_TerapagosTerastal,
|
||||
//.backPicSize = MON_COORDS_SIZE(64, 64),
|
||||
.frontAnimId = ANIM_V_SQUISH_AND_BOUNCE,
|
||||
.enemyMonElevation = 1,
|
||||
.backPic = gMonBackPic_TerapagosTerastal,
|
||||
.backPicSize = MON_COORDS_SIZE(64, 64),
|
||||
.backPicYOffset = 0,
|
||||
//.backAnimId = BACK_ANIM_NONE,
|
||||
//.palette = gMonPalette_TerapagosTerastal,
|
||||
//.shinyPalette = gMonShinyPalette_TerapagosTerastal,
|
||||
.backAnimId = BACK_ANIM_NONE,
|
||||
.palette = gMonPalette_TerapagosTerastal,
|
||||
.shinyPalette = gMonShinyPalette_TerapagosTerastal,
|
||||
.iconSprite = gMonIcon_TerapagosTerastal,
|
||||
.iconPalIndex = 0,
|
||||
FOOTPRINT(TerapagosTerastal)
|
||||
|
||||
@ -10120,8 +10120,20 @@ PLACEHOLDER_ANIM_SINGLE_FRAME(IronCrown);
|
||||
#endif //P_FAMILY_IRON_CROWN
|
||||
|
||||
#if P_FAMILY_TERAPAGOS
|
||||
PLACEHOLDER_ANIM_SINGLE_FRAME(TerapagosNormal);
|
||||
PLACEHOLDER_ANIM_SINGLE_FRAME(TerapagosTerastal);
|
||||
static const union AnimCmd sAnim_TerapagosNormal_1[] =
|
||||
{
|
||||
ANIMCMD_FRAME(0, 30),
|
||||
ANIMCMD_FRAME(1, 30),
|
||||
ANIMCMD_FRAME(0, 1),
|
||||
ANIMCMD_END,
|
||||
};
|
||||
static const union AnimCmd sAnim_TerapagosTerastal_1[] =
|
||||
{
|
||||
ANIMCMD_FRAME(0, 30),
|
||||
ANIMCMD_FRAME(1, 30),
|
||||
ANIMCMD_FRAME(0, 1),
|
||||
ANIMCMD_END,
|
||||
};
|
||||
PLACEHOLDER_ANIM_SINGLE_FRAME(TerapagosStellar);
|
||||
#endif //P_FAMILY_TERAPAGOS
|
||||
|
||||
|
||||
423
src/data/types_info.h
Normal file
423
src/data/types_info.h
Normal file
@ -0,0 +1,423 @@
|
||||
#include "constants/battle.h"
|
||||
#include "constants/pokemon.h"
|
||||
|
||||
#define X UQ_4_12
|
||||
#define ______ X(1.0) // Regular effectiveness.
|
||||
|
||||
// Type matchup updates. Attacker Defender
|
||||
#define STL_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_6 ? X(1.0) : X(0.5)) // Ghost/Dark -> Steel
|
||||
#define PSN_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(2.0)) // Bug -> Poison
|
||||
#define BUG_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(1.0) : X(2.0)) // Poison -> Bug
|
||||
#define PSY_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(2.0) : X(0.0)) // Ghost -> Psychic
|
||||
#define FIR_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(1.0)) // Ice -> Fire
|
||||
|
||||
const uq4_12_t gTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES] =
|
||||
{// Defender -->
|
||||
// Attacker None Normal Fighting Flying Poison Ground Rock Bug Ghost Steel Mystery Fire Water Grass Electric Psychic Ice Dragon Dark Fairy Stellar
|
||||
[TYPE_NONE] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______},
|
||||
[TYPE_NORMAL] = {______, ______, ______, ______, ______, ______, X(0.5), ______, X(0.0), X(0.5), ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______},
|
||||
[TYPE_FIGHTING] = {______, X(2.0), ______, X(0.5), X(0.5), ______, X(2.0), X(0.5), X(0.0), X(2.0), ______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), X(0.5), ______},
|
||||
[TYPE_FLYING] = {______, ______, X(2.0), ______, ______, ______, X(0.5), X(2.0), ______, X(0.5), ______, ______, ______, X(2.0), X(0.5), ______, ______, ______, ______, ______, ______},
|
||||
[TYPE_POISON] = {______, ______, ______, ______, X(0.5), X(0.5), X(0.5), BUG_RS, X(0.5), X(0.0), ______, ______, ______, X(2.0), ______, ______, ______, ______, ______, X(2.0), ______},
|
||||
[TYPE_GROUND] = {______, ______, ______, X(0.0), X(2.0), ______, X(2.0), X(0.5), ______, X(2.0), ______, X(2.0), ______, X(0.5), X(2.0), ______, ______, ______, ______, ______, ______},
|
||||
[TYPE_ROCK] = {______, ______, X(0.5), X(2.0), ______, X(0.5), ______, X(2.0), ______, X(0.5), ______, X(2.0), ______, ______, ______, ______, X(2.0), ______, ______, ______, ______},
|
||||
[TYPE_BUG] = {______, ______, X(0.5), X(0.5), PSN_RS, ______, ______, ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, X(2.0), ______, ______, X(2.0), X(0.5), ______},
|
||||
[TYPE_GHOST] = {______, X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, PSY_RS, ______, ______, X(0.5), ______, ______},
|
||||
[TYPE_STEEL] = {______, ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, ______, X(2.0), ______},
|
||||
[TYPE_MYSTERY] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______},
|
||||
[TYPE_FIRE] = {______, ______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), ______, X(0.5), X(0.5), X(2.0), ______, ______, X(2.0), X(0.5), ______, ______, ______},
|
||||
[TYPE_WATER] = {______, ______, ______, ______, ______, X(2.0), X(2.0), ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______},
|
||||
[TYPE_GRASS] = {______, ______, ______, X(0.5), X(0.5), X(2.0), X(2.0), X(0.5), ______, X(0.5), ______, X(0.5), X(2.0), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______},
|
||||
[TYPE_ELECTRIC] = {______, ______, ______, X(2.0), ______, X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, X(0.5), ______, ______, ______},
|
||||
[TYPE_PSYCHIC] = {______, ______, X(2.0), ______, X(2.0), ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, X(0.5), ______, ______, X(0.0), ______, ______},
|
||||
[TYPE_ICE] = {______, ______, ______, X(2.0), ______, X(2.0), ______, ______, ______, X(0.5), ______, FIR_RS, X(0.5), X(2.0), ______, ______, X(0.5), X(2.0), ______, ______, ______},
|
||||
[TYPE_DRAGON] = {______, ______, ______, ______, ______, ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, ______, ______, X(2.0), ______, X(0.0), ______},
|
||||
[TYPE_DARK] = {______, ______, X(0.5), ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), X(0.5), ______},
|
||||
[TYPE_FAIRY] = {______, ______, X(2.0), ______, X(0.5), ______, ______, ______, ______, X(0.5), ______, X(0.5), ______, ______, ______, ______, ______, X(2.0), X(2.0), ______, ______},
|
||||
[TYPE_STELLAR] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______},
|
||||
};
|
||||
|
||||
#undef ______
|
||||
#undef X
|
||||
|
||||
#if B_EXPANDED_TYPE_NAMES == TRUE
|
||||
#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(DEFAULT(_name, __VA_ARGS__))
|
||||
#else
|
||||
#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(_name)
|
||||
#endif
|
||||
|
||||
// .generic is large enough that the text for TYPE_ELECTRIC will exceed TEXT_BUFF_ARRAY_COUNT.
|
||||
// In this array there's commented-out data such as references to type-resist berries that would otherwise would go unused.
|
||||
// However, we figured this information would be useful for users that want to add their own types as a reminder of
|
||||
// what data would they need to add in order to have their new types be fully fledged like official types.
|
||||
const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] =
|
||||
{
|
||||
[TYPE_NONE] =
|
||||
{
|
||||
.name = _("None"),
|
||||
.generic = _("a move"),
|
||||
.palette = 15, // Uses TYPE_MYSTERY's icon
|
||||
.teraTypeRGBValue = RGB_WHITE,
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_NormalTMHM,
|
||||
},
|
||||
[TYPE_NORMAL] =
|
||||
{
|
||||
.name = _("Normal"),
|
||||
.generic = _("a NORMAL move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_BREAKNECK_BLITZ,
|
||||
.maxMove = MOVE_MAX_STRIKE,
|
||||
.teraTypeRGBValue = RGB_WHITE, // custom
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_NormalTMHM,
|
||||
//.enhanceItem = ITEM_SILK_SCARF,
|
||||
//.berry = ITEM_CHILAN_BERRY,
|
||||
//.gem = ITEM_NORMAL_GEM,
|
||||
//.zCrystal = ITEM_NORMALIUM_Z,
|
||||
//.teraShard = ITEM_NORMAL_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_NORMAL,
|
||||
},
|
||||
[TYPE_FIGHTING] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_TYPE_NAME("Fight", "Fighting"),
|
||||
.generic = _("a FIGHTING move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_ALL_OUT_PUMMELING,
|
||||
.maxMove = MOVE_MAX_KNUCKLE,
|
||||
.teraTypeRGBValue = RGB(26, 8, 14),
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_FightingTMHM,
|
||||
//.enhanceItem = ITEM_BLACK_BELT,
|
||||
//.berry = ITEM_CHOPLE_BERRY,
|
||||
//.gem = ITEM_FIGHTING_GEM,
|
||||
//.zCrystal = ITEM_FIGHTINIUM_Z,
|
||||
//.plate = ITEM_FIST_PLATE,
|
||||
//.memory = ITEM_FIGHTING_MEMORY,
|
||||
//.teraShard = ITEM_FIGHTING_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_FIGHTING,
|
||||
},
|
||||
[TYPE_FLYING] =
|
||||
{
|
||||
.name = _("Flying"),
|
||||
.generic = _("a FLYING move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_SUPERSONIC_SKYSTRIKE,
|
||||
.maxMove = MOVE_MAX_AIRSTREAM,
|
||||
.teraTypeRGBValue = RGB(31, 26, 7),
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_FlyingTMHM,
|
||||
//.enhanceItem = ITEM_SHARP_BEAK,
|
||||
//.berry = ITEM_COBA_BERRY,
|
||||
//.gem = ITEM_FLYING_GEM,
|
||||
//.zCrystal = ITEM_FLYINIUM_Z,
|
||||
//.plate = ITEM_SKY_PLATE,
|
||||
//.memory = ITEM_FLYING_MEMORY,
|
||||
//.teraShard = ITEM_FLYING_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_FLYING,
|
||||
},
|
||||
[TYPE_POISON] =
|
||||
{
|
||||
.name = _("Poison"),
|
||||
.generic = _("a POISON move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_ACID_DOWNPOUR,
|
||||
.maxMove = MOVE_MAX_OOZE,
|
||||
.teraTypeRGBValue = RGB(26, 10, 25), // custom
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_PoisonTMHM,
|
||||
//.enhanceItem = ITEM_POISON_BARB,
|
||||
//.berry = ITEM_KEBIA_BERRY,
|
||||
//.gem = ITEM_POISON_GEM,
|
||||
//.zCrystal = ITEM_POISONIUM_Z,
|
||||
//.plate = ITEM_TOXIC_PLATE,
|
||||
//.memory = ITEM_POISON_MEMORY,
|
||||
//.teraShard = ITEM_POISON_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_POISON,
|
||||
},
|
||||
[TYPE_GROUND] =
|
||||
{
|
||||
.name = _("Ground"),
|
||||
.generic = _("a GROUND move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_TECTONIC_RAGE,
|
||||
.maxMove = MOVE_MAX_QUAKE,
|
||||
.teraTypeRGBValue = RGB(25, 23, 18),
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_GroundTMHM,
|
||||
//.enhanceItem = ITEM_SOFT_SAND,
|
||||
//.berry = ITEM_SHUCA_BERRY,
|
||||
//.gem = ITEM_GROUND_GEM,
|
||||
//.zCrystal = ITEM_GROUNDIUM_Z,
|
||||
//.plate = ITEM_EARTH_PLATE,
|
||||
//.memory = ITEM_GROUND_MEMORY,
|
||||
//.teraShard = ITEM_GROUND_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_GROUND,
|
||||
},
|
||||
[TYPE_ROCK] =
|
||||
{
|
||||
.name = _("Rock"),
|
||||
.generic = _("a ROCK move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_CONTINENTAL_CRUSH,
|
||||
.maxMove = MOVE_MAX_ROCKFALL,
|
||||
.teraTypeRGBValue = RGB(18, 16, 8), // custom
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_RockTMHM,
|
||||
//.enhanceItem = ITEM_HARD_STONE,
|
||||
//.berry = ITEM_CHARTI_BERRY,
|
||||
//.gem = ITEM_ROCK_GEM,
|
||||
//.zCrystal = ITEM_ROCKIUM_Z,
|
||||
//.plate = ITEM_STONE_PLATE,
|
||||
//.memory = ITEM_ROCK_MEMORY,
|
||||
//.teraShard = ITEM_ROCK_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_ROCK,
|
||||
},
|
||||
[TYPE_BUG] =
|
||||
{
|
||||
.name = _("Bug"),
|
||||
.generic = _("a BUG move"),
|
||||
.palette = 15,
|
||||
.zMove = MOVE_SAVAGE_SPIN_OUT,
|
||||
.maxMove = MOVE_MAX_FLUTTERBY,
|
||||
.teraTypeRGBValue = RGB(18, 24, 6),
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_BugTMHM,
|
||||
//.enhanceItem = ITEM_SILVER_POWDER,
|
||||
//.berry = ITEM_TANGA_BERRY,
|
||||
//.gem = ITEM_BUG_GEM,
|
||||
//.zCrystal = ITEM_BUGINIUM_Z,
|
||||
//.plate = ITEM_INSECT_PLATE,
|
||||
//.memory = ITEM_BUG_MEMORY,
|
||||
//.teraShard = ITEM_BUG_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_BUG,
|
||||
},
|
||||
[TYPE_GHOST] =
|
||||
{
|
||||
.name = _("Ghost"),
|
||||
.generic = _("a GHOST move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_NEVER_ENDING_NIGHTMARE,
|
||||
.maxMove = MOVE_MAX_PHANTASM,
|
||||
.teraTypeRGBValue = RGB(12, 10, 16),
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_GhostTMHM,
|
||||
//.enhanceItem = ITEM_SPELL_TAG,
|
||||
//.berry = ITEM_KASIB_BERRY,
|
||||
//.gem = ITEM_GHOST_GEM,
|
||||
//.zCrystal = ITEM_GHOSTIUM_Z,
|
||||
//.plate = ITEM_SPOOKY_PLATE,
|
||||
//.memory = ITEM_GHOST_MEMORY,
|
||||
//.teraShard = ITEM_GHOST_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_GHOST,
|
||||
},
|
||||
[TYPE_STEEL] =
|
||||
{
|
||||
.name = _("Steel"),
|
||||
.generic = _("a STEEL move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_CORKSCREW_CRASH,
|
||||
.maxMove = MOVE_MAX_STEELSPIKE,
|
||||
.teraTypeRGBValue = RGB(19, 19, 20),
|
||||
.damageCategory = DAMAGE_CATEGORY_PHYSICAL,
|
||||
.paletteTMHM = gItemIconPalette_SteelTMHM,
|
||||
//.enhanceItem = ITEM_METAL_COAT,
|
||||
//.berry = ITEM_BABIRI_BERRY,
|
||||
//.gem = ITEM_STEEL_GEM,
|
||||
//.zCrystal = ITEM_STEELIUM_Z,
|
||||
//.plate = ITEM_IRON_PLATE,
|
||||
//.memory = ITEM_STEEL_MEMORY,
|
||||
//.teraShard = ITEM_STEEL_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_STEEL,
|
||||
},
|
||||
[TYPE_MYSTERY] =
|
||||
{
|
||||
.name = _("???"),
|
||||
.generic = _("a ??? move"),
|
||||
.palette = 15,
|
||||
.teraTypeRGBValue = RGB_WHITE,
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
},
|
||||
[TYPE_FIRE] =
|
||||
{
|
||||
.name = _("Fire"),
|
||||
.generic = _("a FIRE move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_INFERNO_OVERDRIVE,
|
||||
.maxMove = MOVE_MAX_FLARE,
|
||||
.teraTypeRGBValue = RGB(31, 20, 11),
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
.paletteTMHM = gItemIconPalette_FireTMHM,
|
||||
//.enhanceItem = ITEM_CHARCOAL,
|
||||
//.berry = ITEM_OCCA_BERRY,
|
||||
//.gem = ITEM_FIRE_GEM,
|
||||
//.zCrystal = ITEM_FIRIUM_Z,
|
||||
//.plate = ITEM_FLAME_PLATE,
|
||||
//.memory = ITEM_FIRE_MEMORY,
|
||||
//.teraShard = ITEM_FIRE_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_FIRE,
|
||||
},
|
||||
[TYPE_WATER] =
|
||||
{
|
||||
.name = _("Water"),
|
||||
.generic = _("a WATER move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_HYDRO_VORTEX,
|
||||
.maxMove = MOVE_MAX_GEYSER,
|
||||
.teraTypeRGBValue = RGB(10, 18, 27),
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
.paletteTMHM = gItemIconPalette_WaterTMHM,
|
||||
//.enhanceItem = ITEM_MYSTIC_WATER,
|
||||
//.berry = ITEM_PASSHO_BERRY,
|
||||
//.gem = ITEM_WATER_GEM,
|
||||
//.zCrystal = ITEM_WATERIUM_Z,
|
||||
//.plate = ITEM_SPLASH_PLATE,
|
||||
//.memory = ITEM_WATER_MEMORY,
|
||||
//.teraShard = ITEM_WATER_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_WATER,
|
||||
},
|
||||
[TYPE_GRASS] =
|
||||
{
|
||||
.name = _("Grass"),
|
||||
.generic = _("a GRASS move"),
|
||||
.palette = 15,
|
||||
.zMove = MOVE_BLOOM_DOOM,
|
||||
.maxMove = MOVE_MAX_OVERGROWTH,
|
||||
.teraTypeRGBValue = RGB(12, 24, 11),
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
.paletteTMHM = gItemIconPalette_GrassTMHM,
|
||||
//.enhanceItem = ITEM_MIRACLE_SEED,
|
||||
//.berry = ITEM_RINDO_BERRY,
|
||||
//.gem = ITEM_GRASS_GEM,
|
||||
//.zCrystal = ITEM_GRASSIUM_Z,
|
||||
//.plate = ITEM_MEADOW_PLATE,
|
||||
//.memory = ITEM_GRASS_MEMORY,
|
||||
//.teraShard = ITEM_GRASS_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_GRASS,
|
||||
},
|
||||
[TYPE_ELECTRIC] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_TYPE_NAME("Electr", "Electric"),
|
||||
.generic = _("an ELECTRIC move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_GIGAVOLT_HAVOC,
|
||||
.maxMove = MOVE_MAX_LIGHTNING,
|
||||
.teraTypeRGBValue = RGB(30, 26, 7),
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
.paletteTMHM = gItemIconPalette_ElectricTMHM,
|
||||
//.enhanceItem = ITEM_MAGNET,
|
||||
//.berry = ITEM_WACAN_BERRY,
|
||||
//.gem = ITEM_ELECTRIC_GEM,
|
||||
//.zCrystal = ITEM_ELECTRIUM_Z,
|
||||
//.plate = ITEM_ZAP_PLATE,
|
||||
//.memory = ITEM_ELECTRIC_MEMORY,
|
||||
//.teraShard = ITEM_ELECTRIC_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_ELECTRIC,
|
||||
},
|
||||
[TYPE_PSYCHIC] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_TYPE_NAME("Psychc", "Psychic"),
|
||||
.generic = _("a PSYCHIC move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_SHATTERED_PSYCHE,
|
||||
.maxMove = MOVE_MAX_MINDSTORM,
|
||||
.teraTypeRGBValue = RGB(31, 14, 15),
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
.paletteTMHM = gItemIconPalette_PsychicTMHM,
|
||||
//.enhanceItem = ITEM_TWISTED_SPOON,
|
||||
//.berry = ITEM_PAYAPA_BERRY,
|
||||
//.gem = ITEM_PSYCHIC_GEM,
|
||||
//.zCrystal = ITEM_PSYCHIUM_Z,
|
||||
//.plate = ITEM_MIND_PLATE,
|
||||
//.memory = ITEM_PSYCHIC_MEMORY,
|
||||
//.teraShard = ITEM_PSYCHIC_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_PSYCHIC,
|
||||
},
|
||||
[TYPE_ICE] =
|
||||
{
|
||||
.name = _("Ice"),
|
||||
.generic = _("an ICE move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_SUBZERO_SLAMMER,
|
||||
.maxMove = MOVE_MAX_HAILSTORM,
|
||||
.teraTypeRGBValue = RGB(14, 26, 25),
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
.paletteTMHM = gItemIconPalette_IceTMHM,
|
||||
//.enhanceItem = ITEM_NEVER_MELT_ICE,
|
||||
//.berry = ITEM_YACHE_BERRY,
|
||||
//.gem = ITEM_ICE_GEM,
|
||||
//.zCrystal = ITEM_ICIUM_Z,
|
||||
//.plate = ITEM_ICICLE_PLATE,
|
||||
//.memory = ITEM_ICE_MEMORY,
|
||||
//.teraShard = ITEM_ICE_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_ICE,
|
||||
},
|
||||
[TYPE_DRAGON] =
|
||||
{
|
||||
.name = _("Dragon"),
|
||||
.generic = _("a DRAGON move"),
|
||||
.palette = 15,
|
||||
.zMove = MOVE_DEVASTATING_DRAKE,
|
||||
.maxMove = MOVE_MAX_WYRMWIND,
|
||||
.teraTypeRGBValue = RGB(10, 18, 27),
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
.paletteTMHM = gItemIconPalette_DragonTMHM,
|
||||
//.enhanceItem = ITEM_DRAGON_FANG,
|
||||
//.berry = ITEM_HABAN_BERRY,
|
||||
//.gem = ITEM_DRAGON_GEM,
|
||||
//.zCrystal = ITEM_DRAGONIUM_Z,
|
||||
//.plate = ITEM_DRACO_PLATE,
|
||||
//.memory = ITEM_DRAGON_MEMORY,
|
||||
//.teraShard = ITEM_DRAGON_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_DRAGON,
|
||||
},
|
||||
[TYPE_DARK] =
|
||||
{
|
||||
.name = _("Dark"),
|
||||
.generic = _("a DARK move"),
|
||||
.palette = 13,
|
||||
.zMove = MOVE_BLACK_HOLE_ECLIPSE,
|
||||
.maxMove = MOVE_MAX_DARKNESS,
|
||||
.teraTypeRGBValue = RGB(6, 5, 8),
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
.paletteTMHM = gItemIconPalette_DarkTMHM,
|
||||
//.enhanceItem = ITEM_BLACK_GLASSES,
|
||||
//.berry = ITEM_COLBUR_BERRY,
|
||||
//.gem = ITEM_DARK_GEM,
|
||||
//.zCrystal = ITEM_DARKINIUM_Z,
|
||||
//.plate = ITEM_DREAD_PLATE,
|
||||
//.memory = ITEM_DARK_MEMORY,
|
||||
//.teraShard = ITEM_DARK_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_DARK,
|
||||
},
|
||||
[TYPE_FAIRY] =
|
||||
{
|
||||
.name = _("Fairy"),
|
||||
.generic = _("a FAIRY move"),
|
||||
.palette = 14,
|
||||
.zMove = MOVE_TWINKLE_TACKLE,
|
||||
.maxMove = MOVE_MAX_STARFALL,
|
||||
.teraTypeRGBValue = RGB(31, 15, 21),
|
||||
.damageCategory = DAMAGE_CATEGORY_SPECIAL,
|
||||
.paletteTMHM = gItemIconPalette_FairyTMHM,
|
||||
//.enhanceItem = ITEM_FAIRY_FEATHER,
|
||||
//.berry = ITEM_ROSELI_BERRY,
|
||||
//.gem = ITEM_FAIRY_GEM,
|
||||
//.zCrystal = ITEM_FAIRIUM_Z,
|
||||
//.plate = ITEM_PIXIE_PLATE,
|
||||
//.memory = ITEM_FAIRY_MEMORY,
|
||||
//.teraShard = ITEM_FAIRY_TERA_SHARD,
|
||||
//.arceusForm = SPECIES_ARCEUS_FAIRY,
|
||||
},
|
||||
[TYPE_STELLAR] =
|
||||
{
|
||||
.name = HANDLE_EXPANDED_TYPE_NAME("Stellr", "Stellar"),
|
||||
.generic = _("a STELLAR move"),
|
||||
.palette = 15,
|
||||
.zMove = MOVE_BREAKNECK_BLITZ,
|
||||
.maxMove = MOVE_MAX_STRIKE,
|
||||
.teraTypeRGBValue = RGB(10, 18, 27),
|
||||
.paletteTMHM = gItemIconPalette_NormalTMHM, // failsafe
|
||||
// .teraShard = ITEM_STELLAR_TERA_SHARD,
|
||||
},
|
||||
};
|
||||
@ -1629,6 +1629,9 @@ const u32 gPartyMenuPokeball_Pal[] = INCBIN_U32("graphics/party_menu/pokeball.gb
|
||||
const u32 gStatusGfx_Icons[] = INCBIN_U32("graphics/interface/status_icons.4bpp.lz");
|
||||
const u32 gStatusPal_Icons[] = INCBIN_U32("graphics/interface/status_icons.gbapal.lz");
|
||||
|
||||
const u16 gCategoryIcons_Pal[] = INCBIN_U16("graphics/interface/category_icons.gbapal");
|
||||
const u32 gCategoryIcons_Gfx[] = INCBIN_U32("graphics/interface/category_icons.4bpp.lz");
|
||||
|
||||
const u32 gMoveTypes_Gfx[] = INCBIN_U32("graphics/types/move_types.4bpp.lz");
|
||||
const u32 gMoveTypes_Pal[] = INCBIN_U32("graphics/types/move_types.gbapal.lz");
|
||||
|
||||
|
||||
@ -112,6 +112,7 @@ static const u8 sTextColors[] = { TEXT_DYNAMIC_COLOR_6, TEXT_COLOR_WHITE, TEXT_C
|
||||
static const struct MenuInfoIcon sMenuInfoIcons[] =
|
||||
{ // { width, height, offset }
|
||||
{ 12, 12, 0x00 }, // Unused
|
||||
[TYPE_NONE + 1] = { 32, 12, 0xA4 }, // Copy of TYPE_MYSTERY's
|
||||
[TYPE_NORMAL + 1] = { 32, 12, 0x20 },
|
||||
[TYPE_FIGHTING + 1] = { 32, 12, 0x64 },
|
||||
[TYPE_FLYING + 1] = { 32, 12, 0x60 },
|
||||
|
||||
@ -1389,7 +1389,7 @@ static const struct SearchOptionText sDexSearchColorOptions[] =
|
||||
|
||||
static const struct SearchOptionText sDexSearchTypeOptions[NUMBER_OF_MON_TYPES] = // + 2 for "None" and terminator, - 2 for Mystery and Stellar
|
||||
{
|
||||
{gText_DexEmptyString, gText_DexSearchTypeNone},
|
||||
{gText_DexEmptyString, gTypesInfo[TYPE_NONE].name},
|
||||
{gText_DexEmptyString, gTypesInfo[TYPE_NORMAL].name},
|
||||
{gText_DexEmptyString, gTypesInfo[TYPE_FIGHTING].name},
|
||||
{gText_DexEmptyString, gTypesInfo[TYPE_FLYING].name},
|
||||
|
||||
@ -622,60 +622,6 @@ static void DestroyCategoryIcon(void);
|
||||
|
||||
static u16 NationalPokedexNumToSpeciesHGSS(u16 nationalNum);
|
||||
|
||||
#define TAG_CATEGORY_ICONS 30004
|
||||
|
||||
static const u16 sCategoryIcons_Pal[] = INCBIN_U16("graphics/interface/category_icons.gbapal");
|
||||
static const u32 sCategoryIcons_Gfx[] = INCBIN_U32("graphics/interface/category_icons.4bpp.lz");
|
||||
|
||||
static const struct OamData sOamData_CategoryIcons =
|
||||
{
|
||||
.size = SPRITE_SIZE(16x16),
|
||||
.shape = SPRITE_SHAPE(16x16),
|
||||
.priority = 0,
|
||||
};
|
||||
static const struct CompressedSpriteSheet sSpriteSheet_CategoryIcons =
|
||||
{
|
||||
.data = sCategoryIcons_Gfx,
|
||||
.size = 16*16*3/2,
|
||||
.tag = TAG_CATEGORY_ICONS,
|
||||
};
|
||||
static const struct SpritePalette sSpritePal_CategoryIcons =
|
||||
{
|
||||
.data = sCategoryIcons_Pal,
|
||||
.tag = TAG_CATEGORY_ICONS
|
||||
};
|
||||
static const union AnimCmd sSpriteAnim_CategoryIcon0[] =
|
||||
{
|
||||
ANIMCMD_FRAME(0, 0),
|
||||
ANIMCMD_END
|
||||
};
|
||||
static const union AnimCmd sSpriteAnim_CategoryIcon1[] =
|
||||
{
|
||||
ANIMCMD_FRAME(4, 0),
|
||||
ANIMCMD_END
|
||||
};
|
||||
static const union AnimCmd sSpriteAnim_CategoryIcon2[] =
|
||||
{
|
||||
ANIMCMD_FRAME(8, 0),
|
||||
ANIMCMD_END
|
||||
};
|
||||
static const union AnimCmd *const sSpriteAnimTable_CategoryIcons[] =
|
||||
{
|
||||
sSpriteAnim_CategoryIcon0,
|
||||
sSpriteAnim_CategoryIcon1,
|
||||
sSpriteAnim_CategoryIcon2,
|
||||
};
|
||||
static const struct SpriteTemplate sSpriteTemplate_CategoryIcons =
|
||||
{
|
||||
.tileTag = TAG_CATEGORY_ICONS,
|
||||
.paletteTag = TAG_CATEGORY_ICONS,
|
||||
.oam = &sOamData_CategoryIcons,
|
||||
.anims = sSpriteAnimTable_CategoryIcons,
|
||||
.images = NULL,
|
||||
.affineAnims = gDummySpriteAffineAnimTable,
|
||||
.callback = SpriteCallbackDummy
|
||||
};
|
||||
|
||||
//Stat bars by DizzyEgg
|
||||
#define TAG_STAT_BAR 4097
|
||||
#define TAG_STAT_BAR_BG 4098
|
||||
@ -1955,7 +1901,7 @@ static const struct SearchOptionText sDexSearchColorOptions[] =
|
||||
|
||||
static const struct SearchOptionText sDexSearchTypeOptions[NUMBER_OF_MON_TYPES] = // + 2 for "None" and terminator, - 2 for Mystery and Stellar
|
||||
{
|
||||
{gText_DexEmptyString, gText_DexSearchTypeNone},
|
||||
{gText_DexEmptyString, gTypesInfo[TYPE_NONE].name},
|
||||
{gText_DexEmptyString, gTypesInfo[TYPE_NORMAL].name},
|
||||
{gText_DexEmptyString, gTypesInfo[TYPE_FIGHTING].name},
|
||||
{gText_DexEmptyString, gTypesInfo[TYPE_FLYING].name},
|
||||
@ -4769,7 +4715,7 @@ static void LoadTilesetTilemapHGSS(u8 page)
|
||||
static u8 ShowCategoryIcon(u32 category)
|
||||
{
|
||||
if (sPokedexView->categoryIconSpriteId == 0xFF)
|
||||
sPokedexView->categoryIconSpriteId = CreateSprite(&sSpriteTemplate_CategoryIcons, 139, 90, 0);
|
||||
sPokedexView->categoryIconSpriteId = CreateSprite(&gSpriteTemplate_CategoryIcons, 139, 90, 0);
|
||||
|
||||
gSprites[sPokedexView->categoryIconSpriteId].invisible = FALSE;
|
||||
StartSpriteAnim(&gSprites[sPokedexView->categoryIconSpriteId], category);
|
||||
@ -4912,8 +4858,8 @@ static void Task_LoadStatsScreen(u8 taskId)
|
||||
CreateTypeIconSprites();
|
||||
sPokedexView->categoryIconSpriteId = 0xFF;
|
||||
LoadCompressedPalette(gMoveTypes_Pal, 0x1D0, 0x60);
|
||||
LoadCompressedSpriteSheet(&sSpriteSheet_CategoryIcons);
|
||||
LoadSpritePalette(&sSpritePal_CategoryIcons);
|
||||
LoadCompressedSpriteSheet(&gSpriteSheet_CategoryIcons);
|
||||
LoadSpritePalette(&gSpritePal_CategoryIcons);
|
||||
gMain.state++;
|
||||
break;
|
||||
case 4:
|
||||
|
||||
@ -2774,14 +2774,14 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
|
||||
break;
|
||||
case MON_DATA_TERA_TYPE:
|
||||
{
|
||||
if (substruct0->teraType == 0)
|
||||
if (substruct0->teraType == TYPE_NONE)
|
||||
{
|
||||
const u8 *types = gSpeciesInfo[substruct0->species].types;
|
||||
retVal = (boxMon->personality & 0x1) == 0 ? types[0] : types[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = substruct0->teraType - 1;
|
||||
retVal = substruct0->teraType;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3210,7 +3210,7 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
|
||||
{
|
||||
u32 teraType;
|
||||
SET8(teraType);
|
||||
substruct0->teraType = 1 + teraType;
|
||||
substruct0->teraType = teraType;
|
||||
break;
|
||||
}
|
||||
case MON_DATA_EVOLUTION_TRACKER:
|
||||
@ -6840,3 +6840,13 @@ const u8 *GetMoveName(u16 moveId)
|
||||
{
|
||||
return gMovesInfo[moveId].name;
|
||||
}
|
||||
|
||||
const u8 *GetMoveAnimationScript(u16 moveId)
|
||||
{
|
||||
if (gMovesInfo[moveId].battleAnimScript == NULL)
|
||||
{
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "No animation for moveId=%u", moveId);
|
||||
return Move_TACKLE;
|
||||
}
|
||||
return gMovesInfo[moveId].battleAnimScript;
|
||||
}
|
||||
|
||||
@ -740,9 +740,6 @@ static const u8 sMovesPPLayout[] = _("{PP}{DYNAMIC 0}/{DYNAMIC 1}");
|
||||
#define TAG_MON_MARKINGS 30003
|
||||
#define TAG_CATEGORY_ICONS 30004
|
||||
|
||||
static const u16 sCategoryIcons_Pal[] = INCBIN_U16("graphics/interface/category_icons.gbapal");
|
||||
static const u32 sCategoryIcons_Gfx[] = INCBIN_U32("graphics/interface/category_icons.4bpp.lz");
|
||||
|
||||
static const struct OamData sOamData_CategoryIcons =
|
||||
{
|
||||
.size = SPRITE_SIZE(16x16),
|
||||
@ -750,16 +747,16 @@ static const struct OamData sOamData_CategoryIcons =
|
||||
.priority = 0,
|
||||
};
|
||||
|
||||
static const struct CompressedSpriteSheet sSpriteSheet_CategoryIcons =
|
||||
const struct CompressedSpriteSheet gSpriteSheet_CategoryIcons =
|
||||
{
|
||||
.data = sCategoryIcons_Gfx,
|
||||
.data = gCategoryIcons_Gfx,
|
||||
.size = 16*16*3/2,
|
||||
.tag = TAG_CATEGORY_ICONS,
|
||||
};
|
||||
|
||||
static const struct SpritePalette sSpritePal_CategoryIcons =
|
||||
const struct SpritePalette gSpritePal_CategoryIcons =
|
||||
{
|
||||
.data = sCategoryIcons_Pal,
|
||||
.data = gCategoryIcons_Pal,
|
||||
.tag = TAG_CATEGORY_ICONS
|
||||
};
|
||||
|
||||
@ -788,7 +785,7 @@ static const union AnimCmd *const sSpriteAnimTable_CategoryIcons[] =
|
||||
sSpriteAnim_CategoryIcon2,
|
||||
};
|
||||
|
||||
static const struct SpriteTemplate sSpriteTemplate_CategoryIcons =
|
||||
const struct SpriteTemplate gSpriteTemplate_CategoryIcons =
|
||||
{
|
||||
.tileTag = TAG_CATEGORY_ICONS,
|
||||
.paletteTag = TAG_CATEGORY_ICONS,
|
||||
@ -815,6 +812,10 @@ static const struct OamData sOamData_MoveTypes =
|
||||
.paletteNum = 0,
|
||||
.affineParam = 0,
|
||||
};
|
||||
static const union AnimCmd sSpriteAnim_TypeNone[] = {
|
||||
ANIMCMD_FRAME(TYPE_NONE * 8, 0, FALSE, FALSE),
|
||||
ANIMCMD_END
|
||||
};
|
||||
static const union AnimCmd sSpriteAnim_TypeNormal[] = {
|
||||
ANIMCMD_FRAME(TYPE_NORMAL * 8, 0, FALSE, FALSE),
|
||||
ANIMCMD_END
|
||||
@ -916,31 +917,32 @@ static const union AnimCmd sSpriteAnim_CategoryTough[] = {
|
||||
ANIMCMD_END
|
||||
};
|
||||
static const union AnimCmd *const sSpriteAnimTable_MoveTypes[NUMBER_OF_MON_TYPES + CONTEST_CATEGORIES_COUNT] = {
|
||||
sSpriteAnim_TypeNormal,
|
||||
sSpriteAnim_TypeFighting,
|
||||
sSpriteAnim_TypeFlying,
|
||||
sSpriteAnim_TypePoison,
|
||||
sSpriteAnim_TypeGround,
|
||||
sSpriteAnim_TypeRock,
|
||||
sSpriteAnim_TypeBug,
|
||||
sSpriteAnim_TypeGhost,
|
||||
sSpriteAnim_TypeSteel,
|
||||
sSpriteAnim_TypeMystery,
|
||||
sSpriteAnim_TypeFire,
|
||||
sSpriteAnim_TypeWater,
|
||||
sSpriteAnim_TypeGrass,
|
||||
sSpriteAnim_TypeElectric,
|
||||
sSpriteAnim_TypePsychic,
|
||||
sSpriteAnim_TypeIce,
|
||||
sSpriteAnim_TypeDragon,
|
||||
sSpriteAnim_TypeDark,
|
||||
sSpriteAnim_TypeFairy,
|
||||
sSpriteAnim_TypeStellar,
|
||||
sSpriteAnim_CategoryCool,
|
||||
sSpriteAnim_CategoryBeauty,
|
||||
sSpriteAnim_CategoryCute,
|
||||
sSpriteAnim_CategorySmart,
|
||||
sSpriteAnim_CategoryTough,
|
||||
[TYPE_NONE] = sSpriteAnim_TypeNone,
|
||||
[TYPE_NORMAL] = sSpriteAnim_TypeNormal,
|
||||
[TYPE_FIGHTING] = sSpriteAnim_TypeFighting,
|
||||
[TYPE_FLYING] = sSpriteAnim_TypeFlying,
|
||||
[TYPE_POISON] = sSpriteAnim_TypePoison,
|
||||
[TYPE_GROUND] = sSpriteAnim_TypeGround,
|
||||
[TYPE_ROCK] = sSpriteAnim_TypeRock,
|
||||
[TYPE_BUG] = sSpriteAnim_TypeBug,
|
||||
[TYPE_GHOST] = sSpriteAnim_TypeGhost,
|
||||
[TYPE_STEEL] = sSpriteAnim_TypeSteel,
|
||||
[TYPE_MYSTERY] = sSpriteAnim_TypeMystery,
|
||||
[TYPE_FIRE] = sSpriteAnim_TypeFire,
|
||||
[TYPE_WATER] = sSpriteAnim_TypeWater,
|
||||
[TYPE_GRASS] = sSpriteAnim_TypeGrass,
|
||||
[TYPE_ELECTRIC] = sSpriteAnim_TypeElectric,
|
||||
[TYPE_PSYCHIC] = sSpriteAnim_TypePsychic,
|
||||
[TYPE_ICE] = sSpriteAnim_TypeIce,
|
||||
[TYPE_DRAGON] = sSpriteAnim_TypeDragon,
|
||||
[TYPE_DARK] = sSpriteAnim_TypeDark,
|
||||
[TYPE_FAIRY] = sSpriteAnim_TypeFairy,
|
||||
[TYPE_STELLAR] = sSpriteAnim_TypeStellar,
|
||||
[NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_COOL] = sSpriteAnim_CategoryCool,
|
||||
[NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_BEAUTY] = sSpriteAnim_CategoryBeauty,
|
||||
[NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_CUTE] = sSpriteAnim_CategoryCute,
|
||||
[NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_SMART] = sSpriteAnim_CategorySmart,
|
||||
[NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_TOUGH] = sSpriteAnim_CategoryTough,
|
||||
};
|
||||
|
||||
const struct CompressedSpriteSheet gSpriteSheet_MoveTypes =
|
||||
@ -1142,7 +1144,7 @@ static const u16 sMarkings_Pal[] = INCBIN_U16("graphics/summary_screen/markings.
|
||||
static u8 ShowCategoryIcon(u32 category)
|
||||
{
|
||||
if (sMonSummaryScreen->categoryIconSpriteId == 0xFF)
|
||||
sMonSummaryScreen->categoryIconSpriteId = CreateSprite(&sSpriteTemplate_CategoryIcons, 48, 129, 0);
|
||||
sMonSummaryScreen->categoryIconSpriteId = CreateSprite(&gSpriteTemplate_CategoryIcons, 48, 129, 0);
|
||||
|
||||
gSprites[sMonSummaryScreen->categoryIconSpriteId].invisible = FALSE;
|
||||
StartSpriteAnim(&gSprites[sMonSummaryScreen->categoryIconSpriteId], category);
|
||||
@ -1437,8 +1439,8 @@ static bool8 DecompressGraphics(void)
|
||||
break;
|
||||
case 12:
|
||||
LoadCompressedPalette(gMoveTypes_Pal, OBJ_PLTT_ID(13), 3 * PLTT_SIZE_4BPP);
|
||||
LoadCompressedSpriteSheet(&sSpriteSheet_CategoryIcons);
|
||||
LoadSpritePalette(&sSpritePal_CategoryIcons);
|
||||
LoadCompressedSpriteSheet(&gSpriteSheet_CategoryIcons);
|
||||
LoadSpritePalette(&gSpritePal_CategoryIcons);
|
||||
sMonSummaryScreen->switchCounter = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -352,7 +352,7 @@ u32 ScriptGiveMonParameterized(u16 species, u8 level, u16 item, u8 ball, u8 natu
|
||||
|
||||
// tera type
|
||||
if (teraType >= NUMBER_OF_MON_TYPES)
|
||||
teraType = gSpeciesInfo[species].types[0];
|
||||
teraType = TYPE_NONE;
|
||||
SetMonData(&mon, MON_DATA_TERA_TYPE, &teraType);
|
||||
|
||||
// EV and IV
|
||||
|
||||
4
test/battle/ability/armor_tail.c
Normal file
4
test/battle/ability/armor_tail.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// Tests for Armor Tail are handled in test/battle/ability/dazzling.c
|
||||
85
test/battle/ability/ate_abilities.c
Normal file
85
test/battle/ability/ate_abilities.c
Normal file
@ -0,0 +1,85 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL);
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].power > 0);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Galvanize can not turn certain moves into Electric type moves")
|
||||
{
|
||||
u32 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_HIDDEN_POWER; }
|
||||
PARAMETRIZE { move = MOVE_WEATHER_BALL; }
|
||||
PARAMETRIZE { move = MOVE_MULTI_ATTACK; }
|
||||
|
||||
ASSUME(gMovesInfo[MOVE_HIDDEN_POWER].effect == EFFECT_HIDDEN_POWER);
|
||||
ASSUME(gMovesInfo[MOVE_WEATHER_BALL].effect == EFFECT_WEATHER_BALL);
|
||||
ASSUME(gMovesInfo[MOVE_MULTI_ATTACK].effect == EFFECT_CHANGE_TYPE_ON_ITEM);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KRABBY);
|
||||
OPPONENT(SPECIES_GEODUDE_ALOLAN) { Ability(ABILITY_GALVANIZE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NOT MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Galvanize turns a normal type move into Electric")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_KRABBY);
|
||||
OPPONENT(SPECIES_GEODUDE_ALOLAN) { Ability(ABILITY_GALVANIZE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pixilate turns a normal type move into Fairy")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_DRAGONITE);
|
||||
OPPONENT(SPECIES_ALTARIA) { Item(ITEM_ALTARIANITE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TACKLE, megaEvolve: TRUE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Refrigerate turns a normal type move into Ice")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_MEGANIUM);
|
||||
OPPONENT(SPECIES_AMAURA) { Ability(ABILITY_REFRIGERATE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TACKLE, megaEvolve: TRUE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Aerilate turns a normal type move into Flying")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_MEGANIUM);
|
||||
OPPONENT(SPECIES_SALAMENCE) { Item(ITEM_SALAMENCITE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TACKLE, megaEvolve: TRUE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
||||
MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
@ -53,3 +53,76 @@ DOUBLE_BATTLE_TEST("Dancer can copy Teeter Dance and confuse both opposing targe
|
||||
MESSAGE("Wynaut became confused!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dancer triggers from slowest to fastest")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(10); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(50); }
|
||||
OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(3); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_DRAGON_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ABILITY_POPUP(opponentRight, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Dancer doesn't trigger if the original user flinches")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100));
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET)
|
||||
OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_FAKE_OUT); MOVE(player, MOVE_DRAGON_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, opponent);
|
||||
MESSAGE("Wobbuffet flinched!");
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_DANCER);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dancer still triggers if another dancer flinches")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100));
|
||||
ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(10); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(5); }
|
||||
OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(3); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentLeft, MOVE_FAKE_OUT, target: playerLeft); MOVE(playerRight, MOVE_DRAGON_DANCE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_DANCER);
|
||||
MESSAGE("Wobbuffet flinched!");
|
||||
NONE_OF {
|
||||
MESSAGE("Wobbuffet used Dragon Dance!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
}
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_DANCER);
|
||||
MESSAGE("Foe Oricorio used Dragon Dance!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
}
|
||||
}
|
||||
|
||||
52
test/battle/ability/dazzling.c
Normal file
52
test/battle/ability/dazzling.c
Normal file
@ -0,0 +1,52 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority > 0);
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect the user from priority moves")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; }
|
||||
PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; }
|
||||
PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentLeft); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponentRight);
|
||||
ABILITY_POPUP(opponentLeft, ability);
|
||||
MESSAGE("Wobbuffet cannot use Quick Attack!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect users partner from priority moves")
|
||||
{
|
||||
u32 species, ability;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; }
|
||||
PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; }
|
||||
PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_QUICK_ATTACK, target: opponentRight); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponentRight);
|
||||
ABILITY_POPUP(opponentLeft, ability);
|
||||
MESSAGE("Wobbuffet cannot use Quick Attack!");
|
||||
}
|
||||
}
|
||||
70
test/battle/ability/good_as_gold.c
Normal file
70
test/battle/ability/good_as_gold.c
Normal file
@ -0,0 +1,70 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
|
||||
SINGLE_BATTLE_TEST("Good as Gold protects from status moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TOXIC].category == DAMAGE_CATEGORY_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TOXIC); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player);
|
||||
ABILITY_POPUP(opponent, ABILITY_GOOD_AS_GOLD);
|
||||
MESSAGE("It doesn't affect Foe Gholdengo…");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Good as Gold doesn't protect the user from it's own moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_NASTY_PLOT].category == DAMAGE_CATEGORY_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_NASTY_PLOT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_NASTY_PLOT, opponent);
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_GOOD_AS_GOLD);
|
||||
MESSAGE("It doesn't affect Foe Gholdengo…");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Good as Gold doesn't protect from moves that target the field")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].category == DAMAGE_CATEGORY_STATUS);
|
||||
ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].target == MOVE_TARGET_OPPONENTS_FIELD);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, player);
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_GOOD_AS_GOLD);
|
||||
MESSAGE("It doesn't affect Foe Gholdengo…");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Good as Gold protects from partner's status moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_HELPING_HAND].category == DAMAGE_CATEGORY_STATUS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_HELPING_HAND); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HELPING_HAND, opponentRight);
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_GOOD_AS_GOLD);
|
||||
MESSAGE("It doesn't affect Foe Gholdengo…");
|
||||
}
|
||||
}
|
||||
@ -107,9 +107,9 @@ SINGLE_BATTLE_TEST("Intimidate and Eject Button force the opponent to Attack")
|
||||
OPPONENT(SPECIES_HITMONTOP) { Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(player, MOVE_QUICK_ATTACK);
|
||||
MOVE(opponent, MOVE_TACKLE);
|
||||
SEND_OUT(opponent, 1);
|
||||
MOVE(player, MOVE_QUICK_ATTACK);
|
||||
MOVE(opponent, MOVE_TACKLE);
|
||||
SEND_OUT(opponent, 1);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, player);
|
||||
@ -210,3 +210,21 @@ SINGLE_BATTLE_TEST("Intimidate can not further lower opponents Atk stat if it is
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], MIN_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutralizing Gas")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
|
||||
} WHEN {
|
||||
TURN { SWITCH(player, 1); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
|
||||
MESSAGE("Neutralizing Gas filled the area!");
|
||||
MESSAGE("Weezing, that's enough! Come back!");
|
||||
MESSAGE("The effects of Neutralizing Gas wore off!");
|
||||
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
|
||||
MESSAGE("Go! Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
4
test/battle/ability/queenly_majesty.c
Normal file
4
test/battle/ability/queenly_majesty.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// Tests for Queenly Majesty are handled in test/battle/ability/dazzling.c
|
||||
264
test/battle/ai.c
264
test/battle/ai.c
@ -2,26 +2,6 @@
|
||||
#include "test/battle.h"
|
||||
#include "battle_ai_util.h"
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI gets baited by Protect Switch tactics") // This behavior is to be fixed.
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_STUNFISK);
|
||||
PLAYER(SPECIES_PELIPPER);
|
||||
OPPONENT(SPECIES_DARKRAI) { Moves(MOVE_TACKLE, MOVE_PECK, MOVE_EARTHQUAKE, MOVE_THUNDERBOLT); }
|
||||
OPPONENT(SPECIES_SCIZOR) { Moves(MOVE_HYPER_BEAM, MOVE_FACADE, MOVE_GIGA_IMPACT, MOVE_EXTREME_SPEED); }
|
||||
} WHEN {
|
||||
|
||||
TURN { MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); } // E-quake
|
||||
TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); } // E-quake
|
||||
TURN { MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_THUNDERBOLT); } // T-Bolt
|
||||
TURN { SWITCH(player, 0); EXPECT_MOVE(opponent, MOVE_THUNDERBOLT); } // T-Bolt
|
||||
TURN { MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); } // E-quake
|
||||
TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE);} // E-quake
|
||||
TURN { MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_THUNDERBOLT); } // T-Bolt
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI prefers Bubble over Water Gun if it's slower")
|
||||
{
|
||||
u32 speedPlayer, speedAi;
|
||||
@ -526,222 +506,6 @@ AI_SINGLE_BATTLE_TEST("AI will choose either Rock Tomb or Bulldoze if Stat drop
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculation checks whether incoming damage is less than recurring healing to avoid an infinite loop")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_VENUSAUR) { Level(30); Moves(MOVE_TACKLE); }
|
||||
// Opponent party courtesy of Skolgrahd, who triggered the bug in the first place
|
||||
OPPONENT(SPECIES_PIKACHU) { Level(100); Moves(MOVE_ZIPPY_ZAP, MOVE_EXTREME_SPEED, MOVE_IRON_TAIL, MOVE_KNOCK_OFF); }
|
||||
OPPONENT(SPECIES_NINETALES_ALOLAN) { Level(100); Moves(MOVE_AURORA_VEIL, MOVE_BLIZZARD, MOVE_MOONBLAST, MOVE_DISABLE); }
|
||||
OPPONENT(SPECIES_WEAVILE) { Level(100); Moves(MOVE_NIGHT_SLASH, MOVE_TRIPLE_AXEL, MOVE_ICE_SHARD, MOVE_FAKE_OUT); }
|
||||
OPPONENT(SPECIES_DITTO) { Level(100); Moves(MOVE_TRANSFORM); }
|
||||
OPPONENT(SPECIES_TYPHLOSION) { Level(100); Moves(MOVE_ERUPTION, MOVE_HEAT_WAVE, MOVE_FOCUS_BLAST, MOVE_EXTRASENSORY); }
|
||||
OPPONENT(SPECIES_UMBREON) { Level(100); Item(ITEM_LEFTOVERS); Moves(MOVE_FOUL_PLAY, MOVE_SNARL, MOVE_HELPING_HAND, MOVE_THUNDER_WAVE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVES(opponent, MOVE_ZIPPY_ZAP, MOVE_EXTREME_SPEED, MOVE_IRON_TAIL, MOVE_KNOCK_OFF); }
|
||||
} SCENE {
|
||||
MESSAGE("Venusaur fainted!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculation checks whether incoming damage is zero to avoid an infinite loop")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_LEFTOVERS].holdEffect == HOLD_EFFECT_LEFTOVERS);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_BULBASAUR) { Level(5); Moves(MOVE_SWORDS_DANCE, MOVE_WHIRLWIND, MOVE_SAND_ATTACK, MOVE_TAIL_WHIP); }
|
||||
// Scenario courtesy of Duke, who triggered the bug in the first place
|
||||
OPPONENT(SPECIES_GEODUDE) { Level(100); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_GEODUDE) { Level(100); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_NOSEPASS) { Level(100); Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SWORDS_DANCE); EXPECT_MOVES(opponent, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
MESSAGE("Bulbasaur fainted!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Avoid infinite loop if damage taken is equal to recurring healing")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_LEFTOVERS].holdEffect == HOLD_EFFECT_LEFTOVERS);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_MEOWTH_GALARIAN) { Level(100); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); }
|
||||
// Scenario courtesy of Duke, who triggered the bug in the first place
|
||||
OPPONENT(SPECIES_MEOWTH_GALARIAN) { Level(5); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); }
|
||||
OPPONENT(SPECIES_GEODUDE) { Level(5); Moves(MOVE_DOUBLE_EDGE); }
|
||||
OPPONENT(SPECIES_GEODUDE) { Level(5); Moves(MOVE_DOUBLE_EDGE); }
|
||||
OPPONENT(SPECIES_NOSEPASS) { Level(5); Moves(MOVE_DOUBLE_EDGE); }
|
||||
OPPONENT(SPECIES_HOUNDSTONE) { Level(5); Moves(MOVE_NIGHT_SHADE, MOVE_BODY_PRESS, MOVE_WILL_O_WISP, MOVE_PROTECT); Item(ITEM_LEFTOVERS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FAKE_OUT); EXPECT_MOVES(opponent, MOVE_FAKE_OUT); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will not switch in a Pokemon which is slower and gets 1HKOed after fainting")
|
||||
{
|
||||
bool32 alakazamFirst;
|
||||
u32 speedAlakazm;
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
|
||||
PARAMETRIZE{ speedAlakazm = 200; alakazamFirst = TRUE; } // AI will always send out Alakazan as it sees a KO with Focus Blast, even if Alakazam dies before it can get it off
|
||||
PARAMETRIZE{ speedAlakazm = 200; alakazamFirst = FALSE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES lets AI see that Alakazam would be KO'd before it can KO, and won't switch it in
|
||||
PARAMETRIZE{ speedAlakazm = 400; alakazamFirst = TRUE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES recognizes that Alakazam is faster and can KO, and will switch it in
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_PSYCHIC].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
ASSUME(gMovesInfo[MOVE_FOCUS_BLAST].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
ASSUME(gMovesInfo[MOVE_BUBBLE_BEAM].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
ASSUME(gMovesInfo[MOVE_WATER_GUN].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
ASSUME(gMovesInfo[MOVE_STRENGTH].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
PLAYER(SPECIES_WEAVILE) { Speed(300); Ability(ABILITY_SHADOW_TAG); } // Weavile has Shadow Tag, so AI can't switch on the first turn, but has to do it after fainting.
|
||||
OPPONENT(SPECIES_KADABRA) { Speed(200); Moves(MOVE_PSYCHIC, MOVE_DISABLE, MOVE_TAUNT, MOVE_CALM_MIND); }
|
||||
OPPONENT(SPECIES_ALAKAZAM) { Speed(speedAlakazm); Moves(MOVE_FOCUS_BLAST, MOVE_PSYCHIC); } // Alakazam has a move which OHKOes Weavile, but it doesn't matter if he's getting KO-ed first.
|
||||
OPPONENT(SPECIES_BLASTOISE) { Speed(200); Moves(MOVE_BUBBLE_BEAM, MOVE_WATER_GUN, MOVE_LEER, MOVE_STRENGTH); } // Can't OHKO, but survives a hit from Weavile's Night Slash.
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_NIGHT_SLASH) ; EXPECT_SEND_OUT(opponent, alakazamFirst ? 1 : 2); } // AI doesn't send out Alakazam if it gets outsped
|
||||
} SCENE {
|
||||
MESSAGE("Foe Kadabra fainted!");
|
||||
if (alakazamFirst) {
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Alakazam!");
|
||||
} else {
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Blastoise!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI switches if Perish Song is about to kill")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) {Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_CROBAT) {Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PERISH_SONG); }
|
||||
TURN { ; }
|
||||
TURN { ; }
|
||||
TURN { EXPECT_SWITCH(opponent, 1); }
|
||||
} SCENE {
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Crobat!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI considers hazard damage when choosing which Pokemon to switch in")
|
||||
{
|
||||
u32 aiIsSmart = 0;
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
|
||||
PARAMETRIZE{ aiIsSmart = 0; aiSmartSwitchFlags = 0; } // AI doesn't care about hazard damage resulting in Pokemon being KO'd
|
||||
PARAMETRIZE{ aiIsSmart = 1; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES avoids being KO'd as a result of hazards damage
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
PLAYER(SPECIES_MEGANIUM) { Speed(100); SpDefense(328); SpAttack(265); Moves(MOVE_STEALTH_ROCK, MOVE_SURF); } // Meganium does ~56% minimum ~66% maximum, enough to KO Charizard after rocks and never KO Typhlosion after rocks
|
||||
OPPONENT(SPECIES_PONYTA) { Level(5); Speed(5); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_CHARIZARD) { Speed(200); Moves(MOVE_FLAMETHROWER); SpAttack(317); SpDefense(207); MaxHP(297); } // Outspeends and 2HKOs Meganium
|
||||
OPPONENT(SPECIES_TYPHLOSION) { Speed(200); Moves(MOVE_FLAMETHROWER); SpAttack(317); SpDefense(207); MaxHP(297); } // Outspeends and 2HKOs Meganium
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK) ;}
|
||||
TURN { MOVE(player, MOVE_SURF); EXPECT_SEND_OUT(opponent, aiIsSmart ? 2 : 1); } // AI sends out Typhlosion to get the KO with the flag rather than Charizard
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize type matchup + SE move, then type matchup")
|
||||
{
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
u32 move1;
|
||||
u32 move2;
|
||||
u32 expectedIndex;
|
||||
|
||||
PARAMETRIZE{ expectedIndex = 3; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; } // When not smart, AI will only switch in a defensive mon if it has a SE move, otherwise will just default to damage
|
||||
PARAMETRIZE{ expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; }
|
||||
PARAMETRIZE{ expectedIndex = 2; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // When smart, AI will prioritize SE move, but still switch in good type matchup without SE move
|
||||
PARAMETRIZE{ expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
PLAYER(SPECIES_MARSHTOMP) { Level(30); Moves(MOVE_MUD_BOMB, MOVE_WATER_GUN, MOVE_GROWL, MOVE_MUD_SHOT); Speed(5); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_NONE); Speed(6); } // Forces switchout
|
||||
OPPONENT(SPECIES_TANGELA) { Level(30); Moves(move1); Speed(4); }
|
||||
OPPONENT(SPECIES_LOMBRE) { Level(30); Moves(move2); Speed(4); }
|
||||
OPPONENT(SPECIES_HARIYAMA) { Level(30); Moves(MOVE_VITAL_THROW); Speed(4); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_GROWL); EXPECT_SWITCH(opponent, expectedIndex); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize defensive options")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_WING_ATTACK, MOVE_BOOMBURST); Speed(5); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_NONE); Speed(4); } // Forces switchout
|
||||
OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); SpDefense(41); } // Mid battle, AI sends out Aron
|
||||
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Post-KO switches prioritize offensive options")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_WING_ATTACK, MOVE_BOOMBURST); Speed(5); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_TACKLE); Speed(4); }
|
||||
OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); } // Mid battle, AI sends out Aron
|
||||
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SEND_OUT(opponent, 2); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI switches out after sufficient stat drops")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_HITMONTOP) { Level(30); Moves(MOVE_CHARM, MOVE_TACKLE); Ability(ABILITY_INTIMIDATE); Speed(5); }
|
||||
OPPONENT(SPECIES_GRIMER) { Level(30); Moves(MOVE_TACKLE); Speed(4); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CHARM); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will not switch out if Pokemon would faint to hazards unless party member can clear them")
|
||||
{
|
||||
u32 move1;
|
||||
|
||||
PARAMETRIZE{ move1 = MOVE_TACKLE; }
|
||||
PARAMETRIZE{ move1 = MOVE_RAPID_SPIN; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(gMovesInfo[MOVE_RAPID_SPIN].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(gMovesInfo[MOVE_EARTHQUAKE].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(gMovesInfo[MOVE_HEADBUTT].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_HITMONTOP) { Level(30); Moves(MOVE_CHARM, MOVE_TACKLE, MOVE_STEALTH_ROCK, MOVE_EARTHQUAKE); Ability(ABILITY_INTIMIDATE); Speed(5); }
|
||||
OPPONENT(SPECIES_GRIMER) { Level(30); Moves(MOVE_TACKLE); Item(ITEM_FOCUS_SASH); Speed(4); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(30); Moves(MOVE_HEADBUTT, move1); Speed(4); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); }
|
||||
TURN { MOVE(player, MOVE_EARTHQUAKE); }
|
||||
TURN { MOVE(player, MOVE_CHARM); }
|
||||
TURN { // If the AI has a mon that can remove hazards, don't prevent them switching out
|
||||
MOVE(player, MOVE_CHARM);
|
||||
if (move1 == MOVE_RAPID_SPIN)
|
||||
EXPECT_SWITCH(opponent, 1);
|
||||
else if (move1 == MOVE_TACKLE)
|
||||
EXPECT_MOVE(opponent, MOVE_TACKLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("First Impression is preferred on the first turn of the species if it's the best dmg move")
|
||||
{
|
||||
GIVEN {
|
||||
@ -778,34 +542,6 @@ AI_SINGLE_BATTLE_TEST("First Impression is not chosen if it's blocked by certain
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spots in a double battle")
|
||||
{
|
||||
u32 flags;
|
||||
|
||||
PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; }
|
||||
PARAMETRIZE {flags = 0; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags);
|
||||
PLAYER(SPECIES_RATTATA);
|
||||
PLAYER(SPECIES_RATTATA);
|
||||
// No moves to damage player.
|
||||
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); }
|
||||
OPPONENT(SPECIES_HAUNTER) { Moves(MOVE_SHADOW_BALL); }
|
||||
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); }
|
||||
OPPONENT(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_SWITCH(opponentLeft, 3); };
|
||||
} SCENE {
|
||||
MESSAGE("{PKMN} TRAINER LEAF withdrew Gengar!");
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Raticate!");
|
||||
NONE_OF {
|
||||
MESSAGE("{PKMN} TRAINER LEAF withdrew Haunter!");
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Raticate!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI will not choose Burn Up if the user lost the Fire typing")
|
||||
{
|
||||
GIVEN {
|
||||
|
||||
91
test/battle/ai_flag_risky.c
Normal file
91
test/battle/ai_flag_risky.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Mirror Coat against special attackers")
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_MIRROR_COAT].effect == EFFECT_MIRROR_COAT);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GROVYLE].baseSpAttack == 85);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GROVYLE].baseAttack == 65);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
|
||||
PLAYER(SPECIES_GROVYLE) { Level(20); Moves(MOVE_ENERGY_BALL); }
|
||||
OPPONENT(SPECIES_CASTFORM) { Level(20); Moves(MOVE_TACKLE, MOVE_MIRROR_COAT); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ENERGY_BALL) ; EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_MIRROR_COAT : MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Counter against physical attackers")
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_COUNTER].effect == EFFECT_COUNTER);
|
||||
ASSUME(gSpeciesInfo[SPECIES_MARSHTOMP].baseAttack == 85);
|
||||
ASSUME(gSpeciesInfo[SPECIES_MARSHTOMP].baseSpAttack == 60);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
|
||||
PLAYER(SPECIES_MARSHTOMP) { Level(20); Moves(MOVE_WATERFALL); }
|
||||
OPPONENT(SPECIES_CASTFORM) { Level(20); Moves(MOVE_TACKLE, MOVE_COUNTER); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WATERFALL) ; EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_COUNTER : MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will prioritize Revenge if slower")
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_REVENGE].effect == EFFECT_REVENGE);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
|
||||
PLAYER(SPECIES_GROVYLE) { Level(20); Speed(4); Moves(MOVE_ENERGY_BALL); }
|
||||
OPPONENT(SPECIES_CASTFORM) { Level(19); Speed(3); Moves(MOVE_TACKLE, MOVE_REVENGE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ENERGY_BALL) ; EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_REVENGE : MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: Mid-battle switches prioritize offensive options")
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES | aiRiskyFlag);
|
||||
PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_WING_ATTACK, MOVE_BOOMBURST); Speed(5); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_NONE); Speed(4); } // Forces switchout
|
||||
OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); SpDefense(41); } // Mid battle, AI sends out Aron
|
||||
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SWITCH(opponent, aiRiskyFlag? 2 : 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI prefers high damage moves at the expense of accuracy regardless of KO thresholds")
|
||||
{
|
||||
u32 aiRiskyFlag = 0;
|
||||
|
||||
PARAMETRIZE{ aiRiskyFlag = 0; }
|
||||
PARAMETRIZE{ aiRiskyFlag = AI_FLAG_RISKY; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
|
||||
PLAYER(SPECIES_GOLDEEN) { Level(5); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_CASTFORM) { Level(20); Moves(MOVE_THUNDER, MOVE_THUNDERBOLT); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_THUNDER : MOVE_THUNDERBOLT); }
|
||||
}
|
||||
}
|
||||
331
test/battle/ai_switching.c
Normal file
331
test/battle/ai_switching.c
Normal file
@ -0,0 +1,331 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI gets baited by Protect Switch tactics") // This behavior is to be fixed.
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_STUNFISK);
|
||||
PLAYER(SPECIES_PELIPPER);
|
||||
OPPONENT(SPECIES_DARKRAI) { Moves(MOVE_TACKLE, MOVE_PECK, MOVE_EARTHQUAKE, MOVE_THUNDERBOLT); }
|
||||
OPPONENT(SPECIES_SCIZOR) { Moves(MOVE_HYPER_BEAM, MOVE_FACADE, MOVE_GIGA_IMPACT, MOVE_EXTREME_SPEED); }
|
||||
} WHEN {
|
||||
|
||||
TURN { MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); } // E-quake
|
||||
TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); } // E-quake
|
||||
TURN { MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_THUNDERBOLT); } // T-Bolt
|
||||
TURN { SWITCH(player, 0); EXPECT_MOVE(opponent, MOVE_THUNDERBOLT); } // T-Bolt
|
||||
TURN { MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); } // E-quake
|
||||
TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE);} // E-quake
|
||||
TURN { MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_THUNDERBOLT); } // T-Bolt
|
||||
}
|
||||
}
|
||||
|
||||
// General switching behaviour
|
||||
AI_SINGLE_BATTLE_TEST("AI switches if Perish Song is about to kill")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) {Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_CROBAT) {Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_PERISH_SONG); }
|
||||
TURN { ; }
|
||||
TURN { ; }
|
||||
TURN { EXPECT_SWITCH(opponent, 1); }
|
||||
} SCENE {
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Crobat!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spots in a double battle")
|
||||
{
|
||||
u32 flags;
|
||||
|
||||
PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; }
|
||||
PARAMETRIZE {flags = 0; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags);
|
||||
PLAYER(SPECIES_RATTATA);
|
||||
PLAYER(SPECIES_RATTATA);
|
||||
// No moves to damage player.
|
||||
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); }
|
||||
OPPONENT(SPECIES_HAUNTER) { Moves(MOVE_SHADOW_BALL); }
|
||||
OPPONENT(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); }
|
||||
OPPONENT(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); }
|
||||
} WHEN {
|
||||
TURN { EXPECT_SWITCH(opponentLeft, 3); };
|
||||
} SCENE {
|
||||
MESSAGE("{PKMN} TRAINER LEAF withdrew Gengar!");
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Raticate!");
|
||||
NONE_OF {
|
||||
MESSAGE("{PKMN} TRAINER LEAF withdrew Haunter!");
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Raticate!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// General AI_FLAG_SMART_MON_CHOICES behaviour
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculation checks whether incoming damage is less than recurring healing to avoid an infinite loop")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_VENUSAUR) { Level(30); Moves(MOVE_TACKLE); }
|
||||
// Opponent party courtesy of Skolgrahd, who triggered the bug in the first place
|
||||
OPPONENT(SPECIES_PIKACHU) { Level(100); Moves(MOVE_ZIPPY_ZAP, MOVE_EXTREME_SPEED, MOVE_IRON_TAIL, MOVE_KNOCK_OFF); }
|
||||
OPPONENT(SPECIES_NINETALES_ALOLAN) { Level(100); Moves(MOVE_AURORA_VEIL, MOVE_BLIZZARD, MOVE_MOONBLAST, MOVE_DISABLE); }
|
||||
OPPONENT(SPECIES_WEAVILE) { Level(100); Moves(MOVE_NIGHT_SLASH, MOVE_TRIPLE_AXEL, MOVE_ICE_SHARD, MOVE_FAKE_OUT); }
|
||||
OPPONENT(SPECIES_DITTO) { Level(100); Moves(MOVE_TRANSFORM); }
|
||||
OPPONENT(SPECIES_TYPHLOSION) { Level(100); Moves(MOVE_ERUPTION, MOVE_HEAT_WAVE, MOVE_FOCUS_BLAST, MOVE_EXTRASENSORY); }
|
||||
OPPONENT(SPECIES_UMBREON) { Level(100); Item(ITEM_LEFTOVERS); Moves(MOVE_FOUL_PLAY, MOVE_SNARL, MOVE_HELPING_HAND, MOVE_THUNDER_WAVE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVES(opponent, MOVE_ZIPPY_ZAP, MOVE_EXTREME_SPEED, MOVE_IRON_TAIL, MOVE_KNOCK_OFF); }
|
||||
} SCENE {
|
||||
MESSAGE("Venusaur fainted!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculation checks whether incoming damage is zero to avoid an infinite loop")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_LEFTOVERS].holdEffect == HOLD_EFFECT_LEFTOVERS);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_BULBASAUR) { Level(5); Moves(MOVE_SWORDS_DANCE, MOVE_WHIRLWIND, MOVE_SAND_ATTACK, MOVE_TAIL_WHIP); }
|
||||
// Scenario courtesy of Duke, who triggered the bug in the first place
|
||||
OPPONENT(SPECIES_GEODUDE) { Level(100); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_GEODUDE) { Level(100); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_NOSEPASS) { Level(100); Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SWORDS_DANCE); EXPECT_MOVES(opponent, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
MESSAGE("Bulbasaur fainted!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Avoid infinite loop if damage taken is equal to recurring healing")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_LEFTOVERS].holdEffect == HOLD_EFFECT_LEFTOVERS);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_MEOWTH_GALARIAN) { Level(100); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); }
|
||||
// Scenario courtesy of Duke, who triggered the bug in the first place
|
||||
OPPONENT(SPECIES_MEOWTH_GALARIAN) { Level(5); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); }
|
||||
OPPONENT(SPECIES_GEODUDE) { Level(5); Moves(MOVE_DOUBLE_EDGE); }
|
||||
OPPONENT(SPECIES_GEODUDE) { Level(5); Moves(MOVE_DOUBLE_EDGE); }
|
||||
OPPONENT(SPECIES_NOSEPASS) { Level(5); Moves(MOVE_DOUBLE_EDGE); }
|
||||
OPPONENT(SPECIES_HOUNDSTONE) { Level(5); Moves(MOVE_NIGHT_SHADE, MOVE_BODY_PRESS, MOVE_WILL_O_WISP, MOVE_PROTECT); Item(ITEM_LEFTOVERS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FAKE_OUT); EXPECT_MOVES(opponent, MOVE_FAKE_OUT); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will not switch in a Pokemon which is slower and gets 1HKOed after fainting")
|
||||
{
|
||||
bool32 alakazamFirst;
|
||||
u32 speedAlakazm;
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
|
||||
PARAMETRIZE{ speedAlakazm = 200; alakazamFirst = TRUE; } // AI will always send out Alakazan as it sees a KO with Focus Blast, even if Alakazam dies before it can get it off
|
||||
PARAMETRIZE{ speedAlakazm = 200; alakazamFirst = FALSE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES lets AI see that Alakazam would be KO'd before it can KO, and won't switch it in
|
||||
PARAMETRIZE{ speedAlakazm = 400; alakazamFirst = TRUE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES recognizes that Alakazam is faster and can KO, and will switch it in
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_PSYCHIC].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
ASSUME(gMovesInfo[MOVE_FOCUS_BLAST].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
ASSUME(gMovesInfo[MOVE_BUBBLE_BEAM].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
ASSUME(gMovesInfo[MOVE_WATER_GUN].category == DAMAGE_CATEGORY_SPECIAL);
|
||||
ASSUME(gMovesInfo[MOVE_STRENGTH].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
PLAYER(SPECIES_WEAVILE) { Speed(300); Ability(ABILITY_SHADOW_TAG); } // Weavile has Shadow Tag, so AI can't switch on the first turn, but has to do it after fainting.
|
||||
OPPONENT(SPECIES_KADABRA) { Speed(200); Moves(MOVE_PSYCHIC, MOVE_DISABLE, MOVE_TAUNT, MOVE_CALM_MIND); }
|
||||
OPPONENT(SPECIES_ALAKAZAM) { Speed(speedAlakazm); Moves(MOVE_FOCUS_BLAST, MOVE_PSYCHIC); } // Alakazam has a move which OHKOes Weavile, but it doesn't matter if he's getting KO-ed first.
|
||||
OPPONENT(SPECIES_BLASTOISE) { Speed(200); Moves(MOVE_BUBBLE_BEAM, MOVE_WATER_GUN, MOVE_LEER, MOVE_STRENGTH); } // Can't OHKO, but survives a hit from Weavile's Night Slash.
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_NIGHT_SLASH) ; EXPECT_SEND_OUT(opponent, alakazamFirst ? 1 : 2); } // AI doesn't send out Alakazam if it gets outsped
|
||||
} SCENE {
|
||||
MESSAGE("Foe Kadabra fainted!");
|
||||
if (alakazamFirst) {
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Alakazam!");
|
||||
} else {
|
||||
MESSAGE("{PKMN} TRAINER LEAF sent out Blastoise!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI considers hazard damage when choosing which Pokemon to switch in")
|
||||
{
|
||||
u32 aiIsSmart = 0;
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
|
||||
PARAMETRIZE{ aiIsSmart = 0; aiSmartSwitchFlags = 0; } // AI doesn't care about hazard damage resulting in Pokemon being KO'd
|
||||
PARAMETRIZE{ aiIsSmart = 1; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES avoids being KO'd as a result of hazards damage
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
PLAYER(SPECIES_MEGANIUM) { Speed(100); SpDefense(328); SpAttack(265); Moves(MOVE_STEALTH_ROCK, MOVE_SURF); } // Meganium does ~56% minimum ~66% maximum, enough to KO Charizard after rocks and never KO Typhlosion after rocks
|
||||
OPPONENT(SPECIES_PONYTA) { Level(5); Speed(5); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_CHARIZARD) { Speed(200); Moves(MOVE_FLAMETHROWER); SpAttack(317); SpDefense(207); MaxHP(297); } // Outspeends and 2HKOs Meganium
|
||||
OPPONENT(SPECIES_TYPHLOSION) { Speed(200); Moves(MOVE_FLAMETHROWER); SpAttack(317); SpDefense(207); MaxHP(297); } // Outspeends and 2HKOs Meganium
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK) ;}
|
||||
TURN { MOVE(player, MOVE_SURF); EXPECT_SEND_OUT(opponent, aiIsSmart ? 2 : 1); } // AI sends out Typhlosion to get the KO with the flag rather than Charizard
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize type matchup + SE move, then type matchup")
|
||||
{
|
||||
u32 aiSmartSwitchFlags = 0;
|
||||
u32 move1;
|
||||
u32 move2;
|
||||
u32 expectedIndex;
|
||||
|
||||
PARAMETRIZE{ expectedIndex = 3; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; } // When not smart, AI will only switch in a defensive mon if it has a SE move, otherwise will just default to damage
|
||||
PARAMETRIZE{ expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = 0; }
|
||||
PARAMETRIZE{ expectedIndex = 2; move1 = MOVE_TACKLE; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; } // When smart, AI will prioritize SE move, but still switch in good type matchup without SE move
|
||||
PARAMETRIZE{ expectedIndex = 1; move1 = MOVE_GIGA_DRAIN; move2 = MOVE_TACKLE; aiSmartSwitchFlags = AI_FLAG_SMART_MON_CHOICES; }
|
||||
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags);
|
||||
PLAYER(SPECIES_MARSHTOMP) { Level(30); Moves(MOVE_MUD_BOMB, MOVE_WATER_GUN, MOVE_GROWL, MOVE_MUD_SHOT); Speed(5); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_NONE); Speed(6); } // Forces switchout
|
||||
OPPONENT(SPECIES_TANGELA) { Level(30); Moves(move1); Speed(4); }
|
||||
OPPONENT(SPECIES_LOMBRE) { Level(30); Moves(move2); Speed(4); }
|
||||
OPPONENT(SPECIES_HARIYAMA) { Level(30); Moves(MOVE_VITAL_THROW); Speed(4); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_GROWL); EXPECT_SWITCH(opponent, expectedIndex); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize defensive options")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_WING_ATTACK, MOVE_BOOMBURST); Speed(5); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_NONE); Speed(4); } // Forces switchout
|
||||
OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); SpDefense(41); } // Mid battle, AI sends out Aron
|
||||
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Post-KO switches prioritize offensive options")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES);
|
||||
PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_WING_ATTACK, MOVE_BOOMBURST); Speed(5); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_TACKLE); Speed(4); }
|
||||
OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); } // Mid battle, AI sends out Aron
|
||||
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SEND_OUT(opponent, 2); }
|
||||
}
|
||||
}
|
||||
|
||||
// General AI_FLAG_SMART_SWITCHING behaviour
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI switches out after sufficient stat drops")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_HITMONTOP) { Level(30); Moves(MOVE_CHARM, MOVE_TACKLE); Ability(ABILITY_INTIMIDATE); Speed(5); }
|
||||
OPPONENT(SPECIES_GRIMER) { Level(30); Moves(MOVE_TACKLE); Speed(4); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_CHARM); }
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will not switch out if Pokemon would faint to hazards unless party member can clear them")
|
||||
{
|
||||
u32 move1;
|
||||
|
||||
PARAMETRIZE{ move1 = MOVE_TACKLE; }
|
||||
PARAMETRIZE{ move1 = MOVE_RAPID_SPIN; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(gMovesInfo[MOVE_RAPID_SPIN].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(gMovesInfo[MOVE_EARTHQUAKE].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(gMovesInfo[MOVE_HEADBUTT].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
|
||||
PLAYER(SPECIES_HITMONTOP) { Level(30); Moves(MOVE_CHARM, MOVE_TACKLE, MOVE_STEALTH_ROCK, MOVE_EARTHQUAKE); Ability(ABILITY_INTIMIDATE); Speed(5); }
|
||||
OPPONENT(SPECIES_GRIMER) { Level(30); Moves(MOVE_TACKLE); Item(ITEM_FOCUS_SASH); Speed(4); }
|
||||
OPPONENT(SPECIES_PONYTA) { Level(30); Moves(MOVE_HEADBUTT, move1); Speed(4); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); }
|
||||
TURN { MOVE(player, MOVE_EARTHQUAKE); }
|
||||
TURN { MOVE(player, MOVE_CHARM); }
|
||||
TURN { // If the AI has a mon that can remove hazards, don't prevent them switching out
|
||||
MOVE(player, MOVE_CHARM);
|
||||
if (move1 == MOVE_RAPID_SPIN)
|
||||
EXPECT_SWITCH(opponent, 1);
|
||||
else if (move1 == MOVE_TACKLE)
|
||||
EXPECT_MOVE(opponent, MOVE_TACKLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trapping behaviour
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch in trapping mon mid battle")
|
||||
{
|
||||
u32 aiSmartSwitchingFlag = 0;
|
||||
PARAMETRIZE { aiSmartSwitchingFlag = 0; }
|
||||
PARAMETRIZE { aiSmartSwitchingFlag = AI_FLAG_SMART_SWITCHING; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_GOLURK].types[0] == TYPE_GROUND);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GOLURK].types[1] == TYPE_GHOST);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchingFlag);
|
||||
PLAYER(SPECIES_ELECTRODE) { Speed(4); Moves(MOVE_THUNDERBOLT, MOVE_AURA_SPHERE, MOVE_PROTECT); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); };
|
||||
OPPONENT(SPECIES_SNORLAX) { Speed(1); Moves(MOVE_HEADBUTT); }
|
||||
OPPONENT(SPECIES_DUGTRIO) { Speed(3); Ability(ABILITY_ARENA_TRAP); Moves(MOVE_EARTHQUAKE); }
|
||||
OPPONENT(SPECIES_GOLURK) { Speed(5); Moves(MOVE_EARTHQUAKE); }
|
||||
} WHEN {
|
||||
if (aiSmartSwitchingFlag == AI_FLAG_SMART_SWITCHING)
|
||||
TURN { MOVE(player, MOVE_AURA_SPHERE) ; EXPECT_SWITCH(opponent, 1); }
|
||||
else
|
||||
TURN { MOVE(player, MOVE_AURA_SPHERE) ; EXPECT_MOVE(opponent, MOVE_HEADBUTT); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will switch in trapping mon after KO")
|
||||
{
|
||||
u32 aiSmartMonChoicesFlag = 0; // Enables trapping behaviour after KOs
|
||||
PARAMETRIZE { aiSmartMonChoicesFlag = 0; } // No trapping behaviour
|
||||
PARAMETRIZE { aiSmartMonChoicesFlag = AI_FLAG_SMART_MON_CHOICES; } // Traps with mid battle switches
|
||||
GIVEN{
|
||||
ASSUME(gSpeciesInfo[SPECIES_MAWILE].types[0] == TYPE_STEEL);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartMonChoicesFlag);
|
||||
PLAYER(SPECIES_MAWILE) { Speed(2); Moves(MOVE_PROTECT, MOVE_TACKLE); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); }
|
||||
OPPONENT(SPECIES_SNORLAX) { Speed(3); Moves(MOVE_SELF_DESTRUCT); }
|
||||
OPPONENT(SPECIES_MAGNEZONE) { Speed(1); Ability(ABILITY_MAGNET_PULL); Moves(MOVE_SHOCK_WAVE); }
|
||||
OPPONENT(SPECIES_MEGANIUM) { Speed(3); Moves(MOVE_EARTH_POWER); }
|
||||
} WHEN {
|
||||
if (aiSmartMonChoicesFlag == AI_FLAG_SMART_MON_CHOICES)
|
||||
TURN{ MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_SELF_DESTRUCT); EXPECT_SEND_OUT(opponent, 1); }
|
||||
else
|
||||
TURN{ MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_SELF_DESTRUCT); EXPECT_SEND_OUT(opponent, 2); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI won't use trapping behaviour if player only has 1 mon left")
|
||||
{
|
||||
u32 aiSmartMonChoicesFlag = 0; // Enables trapping behaviour after KOs
|
||||
PARAMETRIZE { aiSmartMonChoicesFlag = 0; } // No trapping behaviour
|
||||
PARAMETRIZE { aiSmartMonChoicesFlag = AI_FLAG_SMART_MON_CHOICES; } // Traps with mid battle switches
|
||||
GIVEN{
|
||||
ASSUME(gSpeciesInfo[SPECIES_MAWILE].types[0] == TYPE_STEEL);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartMonChoicesFlag);
|
||||
PLAYER(SPECIES_MAWILE) { Speed(2); Moves(MOVE_PROTECT, MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_SNORLAX) { Speed(3); Moves(MOVE_SELF_DESTRUCT); }
|
||||
OPPONENT(SPECIES_MAGNEZONE) { Speed(1); Ability(ABILITY_MAGNET_PULL); Moves(MOVE_SHOCK_WAVE); }
|
||||
OPPONENT(SPECIES_MEGANIUM) { Speed(3); Moves(MOVE_EARTH_POWER); }
|
||||
} WHEN {
|
||||
TURN{ MOVE(player, MOVE_PROTECT); EXPECT_MOVE(opponent, MOVE_SELF_DESTRUCT); EXPECT_SEND_OUT(opponent, 2); }
|
||||
}
|
||||
}
|
||||
@ -1158,6 +1158,8 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Terror traps both opponents")
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("(DYNAMAX) Baton Pass passes G-Max Terror's escape prevention effect");
|
||||
|
||||
DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Meltdown torments both opponents for 3 turns")
|
||||
{
|
||||
GIVEN {
|
||||
@ -1391,6 +1393,8 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Chi Strike boosts allies' crit chance")
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("(DYNAMAX) Baton Pass doesn't pass G-Max Chi Strike's effect");
|
||||
|
||||
DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Depletion takes away 2 PP from the target's last move")
|
||||
{
|
||||
GIVEN {
|
||||
|
||||
@ -765,6 +765,7 @@ SINGLE_BATTLE_TEST("(TERA) Stellar type's one-time boost factors in dynamically-
|
||||
SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly")
|
||||
{
|
||||
u32 type;
|
||||
PARAMETRIZE { type = TYPE_NONE; }
|
||||
PARAMETRIZE { type = TYPE_NORMAL; }
|
||||
PARAMETRIZE { type = TYPE_FIGHTING; }
|
||||
PARAMETRIZE { type = TYPE_FLYING; }
|
||||
|
||||
@ -3,4 +3,4 @@
|
||||
|
||||
TO_DO_BATTLE_TEST("Aqua Ring recovers 1/16th HP at end of turn");
|
||||
TO_DO_BATTLE_TEST("Aqua Ring can be used under Heal Block but will not heal the user");
|
||||
TO_DO_BATTLE_TEST("Aqua Ring can be Baton Passed");
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Aqua Ring's effect");
|
||||
|
||||
6
test/battle/move_effect/baddy_bad.c
Normal file
6
test/battle/move_effect/baddy_bad.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Baddy Bad sets up Reflect, reducing physical damage");
|
||||
TO_DO_BATTLE_TEST("Baddy Bad's Reflect lasts for 5 turns");
|
||||
TO_DO_BATTLE_TEST("Baddy Bad can still damage the target when Reflect is already set up");
|
||||
54
test/battle/move_effect/baton_pass.c
Normal file
54
test/battle/move_effect/baton_pass.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Baton Pass switches out the user");
|
||||
TO_DO_BATTLE_TEST("Baton Pass fails if there's no valid party Pokémon left");
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes both positive and negative stat changes");
|
||||
TO_DO_BATTLE_TEST("AI doesn't choose Baton Pass if the Ace Pokémon is the last one available to switch in");
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass non-volatile status conditions"); // Status1
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass infatuation");
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass type changes");
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass ability changes");
|
||||
|
||||
//
|
||||
// Move these to the corresponding effect files.
|
||||
//
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes confusion status"); // test/battle/status2/confusion.c
|
||||
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Cursed status"); // test/battle/move_effect/curse.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass Disable's effect"); // test/battle/move_effect/disable.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Dragon Cheer's effect"); // test/battle/move_effect/dragon_cheer.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Fairy lock's escape prevention effect"); // test/battle/move_effect/fairy_lock.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Focus Energy's effect"); // test/battle/move_effect/focus_energy.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Heal Block's effect"); // test/battle/move_effect/heal_block.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass Imprison's effect"); // test/battle/move_effect/imprison.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Ingrain's effect"); // test/battle/move_effect/ingrain.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Magnet Rise's effect"); // test/battle/move_effect/magnet_rise.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes escape prevention primary effect if it's used by the target"); // test/battle/move_effect/mean_look.c (Spider Web, Mean Look, Block)
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass escape prevention primary effects if it's used by the user"); // test/battle/move_effect/mean_look.c (Spider Web, Mean Look, Block)
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass Mimic's learnt move"); // test/battle/move_effect/mimic.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Minimize's evasion but not the weakness to stomping moves"); // test/battle/move_effect/minimize.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes No Retreat's escape prevention effect"); // test/battle/move_effect/no_retreat.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Octolock's escape prevention effect"); // test/battle/move_effect/octolock.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Perish Song's effect"); // test/battle/move_effect/perish_song.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Power Trick's effect"); // test/battle/move_effect/power_trick.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass Rollout's multiplier"); // test/battle/move_effect/rollout.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Sappy Seed's effect"); // test/battle/move_effect/sappy_seed.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass Transformations"); // test/battle/move_effect/transform.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass Yawn's effect"); // test/battle/move_effect/yawn.c
|
||||
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Core Enforcer's effect"); // test/battle/move_effect_secondary/core_enforcer.c
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes escape prevention secondary effect"); // test/battle/move_effect_secondary/prevent_escape.c (Thousand Waves, Spirit Shackle, Anchor Shot)
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't pass escape prevention secondary effect if it's used by the user"); // test/battle/move_effect_secondary/prevent_escape.c (Thousand Waves, Spirit Shackle, Anchor Shot)
|
||||
|
||||
// Unconfirmed by Bulbapedia, should be tested in-game:
|
||||
// - Nightmare
|
||||
// - Encore
|
||||
// - Spotlight
|
||||
// - Taunt
|
||||
// - Throat Chop
|
||||
// - Torment
|
||||
// - Splinters
|
||||
// - Power Boost
|
||||
// - Power Drop
|
||||
// - Guard Boost
|
||||
@ -111,3 +111,6 @@ SINGLE_BATTLE_TEST("Beak Blast burns only when contact moves are used")
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Beak Blast's charging message is shown regardless if it would've missed");
|
||||
TO_DO_BATTLE_TEST("Bulletproof is immune to Beak Blast but not to the burn it causes");
|
||||
|
||||
31
test/battle/move_effect/beat_up.c
Normal file
31
test/battle/move_effect/beat_up.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// General
|
||||
TO_DO_BATTLE_TEST("Beat Up hits the target for each non-fainted, non-statused member in the party");
|
||||
TO_DO_BATTLE_TEST("Beat Up's strikes have each an independent chance of a critical hit");
|
||||
|
||||
// B_BEAT_UP Gen2-4
|
||||
TO_DO_BATTLE_TEST("Beat Up lists each party member's name");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage is typeless");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage doesn't consider STAB");
|
||||
TO_DO_BATTLE_TEST("Beat Up's last strike-only can trigger King's Rock");
|
||||
TO_DO_BATTLE_TEST("Beat Up's base power is the same for each strike");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage is determined by each striking Pokémon's base attack and level and the target's defense");
|
||||
TO_DO_BATTLE_TEST("Beat Up ignores stat stage changes"); //eg. Swords Dance
|
||||
TO_DO_BATTLE_TEST("Beat Up ignores Huge Power");
|
||||
TO_DO_BATTLE_TEST("Beat Up ignores Choice Band");
|
||||
|
||||
// B_BEAT_UP Gen5+
|
||||
TO_DO_BATTLE_TEST("Beat Up doesn't list party member's name");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage is Dark-typed");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage receives STAB");
|
||||
TO_DO_BATTLE_TEST("Beat Up's can trigger King's Rock on all strikes");
|
||||
TO_DO_BATTLE_TEST("Beat Up's base power is determined by each striking Pokémon");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage is determined by the user's attack and the target's defense");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage considers stat stage changes"); //eg. Swords Dance
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage considers Huge Power");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage considers Choice Band");
|
||||
|
||||
// Unconfirmed by Bulbapedia
|
||||
// - Technician interacion
|
||||
@ -39,6 +39,7 @@ SINGLE_BATTLE_TEST("Belch cannot be used if the user has not eaten a berry")
|
||||
else {
|
||||
TURN { MOVE(player, MOVE_STUFF_CHEEKS); }
|
||||
TURN { MOVE(player, MOVE_BELCH); }
|
||||
TURN { MOVE(player, MOVE_BELCH); }
|
||||
}
|
||||
} SCENE {
|
||||
if (item == ITEM_NONE) {
|
||||
@ -47,6 +48,11 @@ SINGLE_BATTLE_TEST("Belch cannot be used if the user has not eaten a berry")
|
||||
else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Belch can still be used after switching out");
|
||||
TO_DO_BATTLE_TEST("Belch can still be used after fainting");
|
||||
TO_DO_BATTLE_TEST("Belch can still be used after restoring the consumed berry");
|
||||
|
||||
@ -104,3 +104,8 @@ SINGLE_BATTLE_TEST("Belly Drum's HP cost doesn't trigger effects that trigger on
|
||||
NOT MESSAGE("Wobbuffet's Air Balloon popped!");
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Belly Drum maximizes the user's Attack stat, even when below 0");
|
||||
TO_DO_BATTLE_TEST("Belly Drum minimizes the user's Attack stat if it has Contrary"); // Should still say "maximized attack"
|
||||
TO_DO_BATTLE_TEST("Belly Drum fails if the user's Attack is already at +6, even with Contrary");
|
||||
TO_DO_BATTLE_TEST("Belly Drum deducts HP if the user has contrary and is at -6");
|
||||
|
||||
10
test/battle/move_effect/bestow.c
Normal file
10
test/battle/move_effect/bestow.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Bestow transfers its held item to the target");
|
||||
TO_DO_BATTLE_TEST("Bestow fails if the user has no held item");
|
||||
TO_DO_BATTLE_TEST("Bestow fails if the target already has a held item");
|
||||
TO_DO_BATTLE_TEST("Bestow fails if the target is behind a Substitute");
|
||||
TO_DO_BATTLE_TEST("Bestow fails if the user is holding Mail");
|
||||
TO_DO_BATTLE_TEST("Bestow fails if the user's held item changes its form");
|
||||
TO_DO_BATTLE_TEST("Bestow fails if the user's held item is a Z-Crystal");
|
||||
@ -32,3 +32,6 @@ SINGLE_BATTLE_TEST("Bide deals twice the taken damage over two turns")
|
||||
EXPECT_EQ(bideDamage, 2 * (damage1 + damage2));
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Bide hits the last Pokémon that attacked the user, even allies");
|
||||
TO_DO_BATTLE_TEST("Bide has +1 priority if called via a different move"); // Gen 5 onwards
|
||||
|
||||
4
test/battle/move_effect/blizzard.c
Normal file
4
test/battle/move_effect/blizzard.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Blizzard ignores accuracy check durin Hail and Snow");
|
||||
@ -4,6 +4,7 @@
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_BODY_PRESS].effect == EFFECT_BODY_PRESS);
|
||||
ASSUME(gMovesInfo[MOVE_BODY_PRESS].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Body Press uses physical defense stat of target", s16 damage)
|
||||
@ -16,6 +17,7 @@ SINGLE_BATTLE_TEST("Body Press uses physical defense stat of target", s16 damage
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_DRILL_PECK].power == gMovesInfo[MOVE_BODY_PRESS].power);
|
||||
ASSUME(gMovesInfo[MOVE_CHARM].effect == EFFECT_ATTACK_DOWN_2);
|
||||
ASSUME(gMovesInfo[MOVE_CHARM].effect == EFFECT_ATTACK_DOWN_2);
|
||||
PLAYER(SPECIES_MEW);
|
||||
OPPONENT(SPECIES_SHELLDER);
|
||||
} WHEN {
|
||||
@ -27,3 +29,13 @@ SINGLE_BATTLE_TEST("Body Press uses physical defense stat of target", s16 damage
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Body Press's damage depends on the user's base Defense instead of its base Attack");
|
||||
TO_DO_BATTLE_TEST("Body Press's damage depends on the user's Defense stat stages");
|
||||
|
||||
// Could be split into multiple tests or maybe to separate files based on the modifier?
|
||||
TO_DO_BATTLE_TEST("Body Press's damage is influenced by all other Attack modifiers that are not stat stages");
|
||||
TO_DO_BATTLE_TEST("Body Press's damage is NOT influenced by any other Defense besides stat stages");
|
||||
|
||||
// Unconfirmed by Bulbapedia:
|
||||
// - Defeatist interaction
|
||||
|
||||
5
test/battle/move_effect/bolt_beak.c
Normal file
5
test/battle/move_effect/bolt_beak.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Bolt Beak's base power is doubled if it attacks before the target");
|
||||
TO_DO_BATTLE_TEST("Bolt Beak's base power is doubled the target switches out");
|
||||
@ -137,24 +137,3 @@ DOUBLE_BATTLE_TEST("Brick Break can remove Light Screen, Reflect and Aurora Veil
|
||||
HP_BAR(playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Move Raging Bull changes it's type depending on the Tauros Form")
|
||||
{
|
||||
u16 speciesPlayer;
|
||||
u16 speciesOpponent;
|
||||
|
||||
PARAMETRIZE { speciesPlayer = SPECIES_TAUROS_PALDEAN_COMBAT_BREED; speciesOpponent = SPECIES_CHARIZARD; }
|
||||
PARAMETRIZE { speciesPlayer = SPECIES_TAUROS_PALDEAN_BLAZE_BREED; speciesOpponent = SPECIES_BLASTOISE; }
|
||||
PARAMETRIZE { speciesPlayer = SPECIES_TAUROS_PALDEAN_AQUA_BREED; speciesOpponent = SPECIES_VENUSAUR; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(speciesPlayer);
|
||||
OPPONENT(speciesOpponent);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_RAGING_BULL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAGING_BULL, player);
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("It's not very effective…");
|
||||
}
|
||||
}
|
||||
|
||||
4
test/battle/move_effect/brine.c
Normal file
4
test/battle/move_effect/brine.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Brine's power doubles if the target is at 50% or below max HP");
|
||||
4
test/battle/move_effect/bulk_up.c
Normal file
4
test/battle/move_effect/bulk_up.c
Normal file
@ -0,0 +1,4 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("Bulk Up increases the user's Attack and Defense");
|
||||
28
test/battle/move_effect/earthquake.c
Normal file
28
test/battle/move_effect/earthquake.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Earthquake's and Bulldoze's damage is halved when Grassy Terrain is in effect", s16 damage)
|
||||
{
|
||||
bool32 terrain;
|
||||
u16 move;
|
||||
PARAMETRIZE { terrain = FALSE; move = MOVE_EARTHQUAKE; } // 0
|
||||
PARAMETRIZE { terrain = TRUE; move = MOVE_EARTHQUAKE; } // 1
|
||||
PARAMETRIZE { terrain = FALSE; move = MOVE_BULLDOZE; } // 2
|
||||
PARAMETRIZE { terrain = TRUE; move = MOVE_BULLDOZE; } // 3
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EARTHQUAKE].effect == EFFECT_EARTHQUAKE);
|
||||
ASSUME(gMovesInfo[MOVE_BULLDOZE].effect == EFFECT_EARTHQUAKE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
if (terrain)
|
||||
TURN { MOVE(player, MOVE_GRASSY_TERRAIN); }
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage);
|
||||
EXPECT_MUL_EQ(results[2].damage, Q_4_12(0.5), results[3].damage);
|
||||
}
|
||||
}
|
||||
@ -203,7 +203,7 @@ SINGLE_BATTLE_TEST("Embargo doesn't stop an item flung at an affected target fro
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Embargo is passed via Baton Pass")
|
||||
SINGLE_BATTLE_TEST("Baton Pass passes Embargo's effect")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
|
||||
@ -39,3 +39,6 @@ SINGLE_BATTLE_TEST("Gastro Acid fails if target has a banned ability")
|
||||
MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Gastro Acid's effect");
|
||||
TO_DO_BATTLE_TEST("Baton Pass removes Gastro Acid if its ability cannot be surpressed");
|
||||
|
||||
106
test/battle/move_effect/hidden_power.c
Normal file
106
test/battle/move_effect/hidden_power.c
Normal file
@ -0,0 +1,106 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// IV combinations sourced from https://www.smogon.com/forums/threads/hidden-power-iv-combinations.78083/
|
||||
SINGLE_BATTLE_TEST("Hidden Power's type is determined by IVs")
|
||||
{
|
||||
u32 type, j, foeType, foeSpecies;
|
||||
u32 hp, atk, def, spAtk, spDef, speed;
|
||||
bool32 hidden;
|
||||
|
||||
PARAMETRIZE { type = TYPE_NONE; hidden = FALSE; }
|
||||
PARAMETRIZE { type = TYPE_NORMAL; hidden = FALSE; }
|
||||
PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 30; }
|
||||
PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_MYSTERY; hidden = FALSE; }
|
||||
PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 3; def = 31; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 23; def = 31; spAtk = 31; spDef = 31; speed = 31; }
|
||||
PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; }
|
||||
|
||||
// Any type after Dark shouldn't be part of Hidden Power officially.
|
||||
for (j = TYPE_DARK + 1; j < NUMBER_OF_MON_TYPES; j++) {
|
||||
PARAMETRIZE { type = j; hidden = FALSE; }
|
||||
}
|
||||
|
||||
GIVEN {
|
||||
if (hidden) {
|
||||
ASSUME(gTypeEffectivenessTable[type][foeType] == UQ_4_12(0.5)); // Foe's Type resists
|
||||
ASSUME(gSpeciesInfo[foeSpecies].types[0] == gSpeciesInfo[foeSpecies].types[1]); // Foe's pure type
|
||||
ASSUME(gSpeciesInfo[foeSpecies].types[0] == foeType); // Foe is the resisted type
|
||||
PLAYER(SPECIES_DUNSPARCE) { HPIV(hp); AttackIV(atk); DefenseIV(def); SpAttackIV(spAtk); SpDefenseIV(spDef); SpeedIV(speed); }
|
||||
} else {
|
||||
PLAYER(SPECIES_DUNSPARCE);
|
||||
}
|
||||
OPPONENT(foeSpecies);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_HIDDEN_POWER); }
|
||||
} SCENE {
|
||||
// Only test valid Hidden Power types
|
||||
if (hidden) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HIDDEN_POWER, player);
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("It's not very effective…");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Hidden Power's power is determined by IVs before Gen6");
|
||||
@ -24,3 +24,4 @@ TO_DO_BATTLE_TEST("Leech Seed doesn't affect already seeded targets")
|
||||
TO_DO_BATTLE_TEST("Leech Seeded targets lose 1/8 of its max HP every turn and give it to the user")
|
||||
TO_DO_BATTLE_TEST("Leech Seed's effect is paused until a new battler replaces the original user's position") // Faint, can't be replaced, then revived.
|
||||
TO_DO_BATTLE_TEST("Leech Seed's effect pause still prevents it from being seeded again")
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Leech Seed's effect");
|
||||
|
||||
@ -24,3 +24,5 @@ SINGLE_BATTLE_TEST("Pursuited mon correctly switches out after it got hit and ac
|
||||
MESSAGE("Go! Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Baton Pass doesn't cause Pursuit to increase its power or priority");
|
||||
|
||||
160
test/battle/move_effect/raging_bull.c
Normal file
160
test/battle/move_effect/raging_bull.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_RAGING_BULL].effect == EFFECT_RAGING_BULL);
|
||||
ASSUME(gMovesInfo[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE);
|
||||
ASSUME(gMovesInfo[MOVE_LIGHT_SCREEN].effect == EFFECT_LIGHT_SCREEN);
|
||||
ASSUME(gMovesInfo[MOVE_REFLECT].effect == EFFECT_REFLECT);
|
||||
ASSUME(gMovesInfo[MOVE_AURORA_VEIL].effect == EFFECT_AURORA_VEIL);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Raging Bull removes Light Screen, Reflect and Aurora Veil from the target's side of the field")
|
||||
{
|
||||
u16 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNOWSCAPE); }
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_RAGING_BULL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAGING_BULL, player);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Raging Bull doesn't remove Light Screen, Reflect and Aurora Veil if the target is immune")
|
||||
{
|
||||
u16 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GASTLY);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNOWSCAPE); }
|
||||
TURN { MOVE(opponent, move); MOVE(player, MOVE_RAGING_BULL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAGING_BULL, player);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Raging Bull doesn't remove Light Screen, Reflect and Aurora Veil if the target Protected")
|
||||
{
|
||||
u16 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNOWSCAPE); MOVE(opponent, move); }
|
||||
TURN { MOVE(player, MOVE_RAGING_BULL); MOVE(opponent, MOVE_PROTECT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAGING_BULL, player);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Raging Bull doesn't remove Light Screen, Reflect and Aurora Veil if it misses")
|
||||
{
|
||||
u16 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BRIGHT_POWDER); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SNOWSCAPE); MOVE(opponent, move); }
|
||||
TURN { MOVE(player, MOVE_RAGING_BULL, hit: FALSE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAGING_BULL, player);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Raging Bull can remove Light Screen, Reflect and Aurora Veil on users side")
|
||||
{
|
||||
u16 move;
|
||||
|
||||
PARAMETRIZE { move = MOVE_LIGHT_SCREEN; }
|
||||
PARAMETRIZE { move = MOVE_REFLECT; }
|
||||
PARAMETRIZE { move = MOVE_AURORA_VEIL; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(opponentLeft, MOVE_SNOWSCAPE);
|
||||
MOVE(playerLeft, move);
|
||||
MOVE(playerRight, MOVE_RAGING_BULL, target: playerLeft);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAGING_BULL, playerRight);
|
||||
MESSAGE("The wall shattered!");
|
||||
HP_BAR(playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Move Raging Bull changes it's type depending on the Tauros Form")
|
||||
{
|
||||
u16 speciesPlayer;
|
||||
u16 speciesOpponent;
|
||||
|
||||
PARAMETRIZE { speciesPlayer = SPECIES_TAUROS_PALDEAN_COMBAT_BREED; speciesOpponent = SPECIES_CHARIZARD; }
|
||||
PARAMETRIZE { speciesPlayer = SPECIES_TAUROS_PALDEAN_BLAZE_BREED; speciesOpponent = SPECIES_BLASTOISE; }
|
||||
PARAMETRIZE { speciesPlayer = SPECIES_TAUROS_PALDEAN_AQUA_BREED; speciesOpponent = SPECIES_VENUSAUR; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(speciesPlayer);
|
||||
OPPONENT(speciesOpponent);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_RAGING_BULL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAGING_BULL, player);
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("It's not very effective…");
|
||||
}
|
||||
}
|
||||
@ -68,3 +68,5 @@ SINGLE_BATTLE_TEST("Substitute's HP cost doesn't trigger effects that trigger on
|
||||
NOT MESSAGE("Wobbuffet's Air Balloon popped!");
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Substitutes");
|
||||
|
||||
@ -68,3 +68,7 @@ SINGLE_BATTLE_TEST("Telekinesis makes the target immune to Ground-type attacks")
|
||||
MESSAGE("It doesn't affect Foe Wynaut…");
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Baton Pass passes Telekinesis' effect");
|
||||
//Bulbapedia doesn't confirm what happens with Diglett, Dugtrio, Sandygast and Palossand, so it needs to be tested in-game.
|
||||
TO_DO_BATTLE_TEST("Baton Pass removes Telekinesis' effect disappears if the switching-in mon is Mega Gengar");
|
||||
|
||||
@ -21,6 +21,57 @@ SINGLE_BATTLE_TEST("Tera Blast changes from Normal-type to the user's Tera Type"
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Tera Blast has correct effectiveness for every Tera Type")
|
||||
{
|
||||
u32 species;
|
||||
u32 type;
|
||||
|
||||
PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_FLYING; }
|
||||
PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_POISON; }
|
||||
PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_FIRE; }
|
||||
PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_BUG; }
|
||||
PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_ICE; }
|
||||
PARAMETRIZE { species = SPECIES_CYNDAQUIL; type = TYPE_GROUND; }
|
||||
PARAMETRIZE { species = SPECIES_CYNDAQUIL; type = TYPE_ROCK; }
|
||||
PARAMETRIZE { species = SPECIES_CYNDAQUIL; type = TYPE_WATER; }
|
||||
PARAMETRIZE { species = SPECIES_GASTLY; type = TYPE_NORMAL; }
|
||||
PARAMETRIZE { species = SPECIES_GASTLY; type = TYPE_GHOST; }
|
||||
PARAMETRIZE { species = SPECIES_GASTLY; type = TYPE_PSYCHIC; }
|
||||
PARAMETRIZE { species = SPECIES_TOTODILE; type = TYPE_GRASS; }
|
||||
PARAMETRIZE { species = SPECIES_TOTODILE; type = TYPE_ELECTRIC; }
|
||||
PARAMETRIZE { species = SPECIES_DRATINI; type = TYPE_DRAGON; }
|
||||
PARAMETRIZE { species = SPECIES_DRATINI; type = TYPE_FAIRY; }
|
||||
PARAMETRIZE { species = SPECIES_SNEASEL; type = TYPE_FIGHTING; }
|
||||
PARAMETRIZE { species = SPECIES_SNEASEL; type = TYPE_STEEL; }
|
||||
PARAMETRIZE { species = SPECIES_ABRA; type = TYPE_DARK; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_CHIKORITA].types[0] == TYPE_GRASS);
|
||||
ASSUME(gSpeciesInfo[SPECIES_CHIKORITA].types[1] == TYPE_GRASS);
|
||||
ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GASTLY].types[0] == TYPE_GHOST);
|
||||
ASSUME(gSpeciesInfo[SPECIES_GASTLY].types[1] == TYPE_POISON);
|
||||
ASSUME(gSpeciesInfo[SPECIES_TOTODILE].types[0] == TYPE_WATER);
|
||||
ASSUME(gSpeciesInfo[SPECIES_TOTODILE].types[1] == TYPE_WATER);
|
||||
ASSUME(gSpeciesInfo[SPECIES_DRATINI].types[0] == TYPE_DRAGON);
|
||||
ASSUME(gSpeciesInfo[SPECIES_DRATINI].types[1] == TYPE_DRAGON);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SNEASEL].types[0] == TYPE_DARK);
|
||||
ASSUME(gSpeciesInfo[SPECIES_SNEASEL].types[1] == TYPE_ICE);
|
||||
ASSUME(gSpeciesInfo[SPECIES_ABRA].types[0] == TYPE_PSYCHIC);
|
||||
ASSUME(gSpeciesInfo[SPECIES_ABRA].types[1] == TYPE_PSYCHIC);
|
||||
PLAYER(SPECIES_WOBBUFFET) { TeraType(type); }
|
||||
OPPONENT(species);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TERA_BLAST, tera: TRUE); }
|
||||
} SCENE {
|
||||
if (species == SPECIES_GASTLY && type == TYPE_NORMAL)
|
||||
MESSAGE("It doesn't affect Foe Gastly…");
|
||||
else
|
||||
MESSAGE("It's super effective!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Tera Blast becomes a physical move if the user is Terastallized and has a higher Attack stat", s16 damage)
|
||||
{
|
||||
bool32 tera;
|
||||
|
||||
@ -57,33 +57,6 @@ SINGLE_BATTLE_TEST("Grassy Terrain increases power of Grass-type moves by 30/50
|
||||
}
|
||||
}
|
||||
|
||||
// Magnitude is not tested because its damage is variable.
|
||||
SINGLE_BATTLE_TEST("Grassy Terrain decreases power of Earthquake and Bulldoze by 50 percent", s16 damage)
|
||||
{
|
||||
bool32 terrain;
|
||||
u16 move;
|
||||
PARAMETRIZE { terrain = FALSE; move = MOVE_EARTHQUAKE; } // 0
|
||||
PARAMETRIZE { terrain = TRUE; move = MOVE_EARTHQUAKE; } // 1
|
||||
PARAMETRIZE { terrain = FALSE; move = MOVE_BULLDOZE; } // 2
|
||||
PARAMETRIZE { terrain = TRUE; move = MOVE_BULLDOZE; } // 3
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EARTHQUAKE].effect == EFFECT_EARTHQUAKE);
|
||||
ASSUME(gMovesInfo[MOVE_BULLDOZE].effect == EFFECT_EARTHQUAKE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
if (terrain)
|
||||
TURN { MOVE(player, MOVE_GRASSY_TERRAIN); }
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage);
|
||||
EXPECT_MUL_EQ(results[2].damage, Q_4_12(0.5), results[3].damage);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Grassy Terrain lasts for 5 turns")
|
||||
{
|
||||
GIVEN {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user