merge w upcoming

This commit is contained in:
ghoulslash 2024-10-15 21:24:47 -04:00
commit cf78462fab
108 changed files with 2830 additions and 1127 deletions

View File

@ -23,9 +23,10 @@ body:
label: Version
description: What version of pokeemerald-expansion are you using as a base?
options:
- 1.9.2 (Latest release)
- 1.9.3 (Latest release)
- master (default, unreleased bugfixes)
- upcoming (Edge)
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.6

View File

@ -23,9 +23,10 @@ body:
label: Version
description: What version of pokeemerald-expansion are you using as a base?
options:
- 1.9.2 (Latest release)
- 1.9.3 (Latest release)
- master (default, unreleased bugfixes)
- upcoming (Edge)
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.6

View File

@ -23,9 +23,10 @@ body:
label: Version
description: What version of pokeemerald-expansion are you using as a base?
options:
- 1.9.2 (Latest release)
- 1.9.3 (Latest release)
- master (default, unreleased bugfixes)
- upcoming (Edge)
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.6

View File

@ -9,7 +9,7 @@ pokeemerald-expansion is a decomp hack base project based off pret's [pokeemeral
If you use pokeemerald-expansion in your hack, please add RHH (Rom Hacking Hideout) to your credits list. Optionally, you can list the version used, so it can help players know what features to expect.
You can phrase it as the following:
```
Based off RHH's pokeemerald-expansion 1.9.2 https://github.com/rh-hideout/pokeemerald-expansion/
Based off RHH's pokeemerald-expansion 1.9.3 https://github.com/rh-hideout/pokeemerald-expansion/
```
## What features are included?
@ -178,7 +178,7 @@ With this, you'll get the latest version of pokeemerald-expansion, plus a couple
- Check your current version.
- You can check in the debug menu's `Utilities -> Expansion Version` option.
- If the option is not available, you possibly have version 1.6.2 or older. In that case, please check the [changelogs](CHANGELOG.md) to determine your version based on the features available on your repository.
- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.9.2, use `git pull RHH expansion/1.9.2`).
- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.9.3, use `git pull RHH expansion/1.9.3`).
- ***Important:*** If you are several versions behind, we recommend updating one minor version at a time, skipping directly to the latest patch version (eg, 1.5.3 -> 1.6.2 -> 1.7.4 and so on)
- Alternatively, you can update to unreleased versions of the expansion.
- ***master (stable):*** It contains unreleased **bugfixes** that will come in the next patch version. To merge, use `git pull RHH master`.

View File

@ -2338,3 +2338,95 @@
.macro hideitemdescription
callnative ScriptHideItemDescription
.endm
@ Remove all of specified item from the player's bag and return the number of removed items to VAR_RESULT
.macro removeallitem itemId:req
callnative ScrCmd_removeallitem
.2byte \itemId
.endm
@ Stores the position of the given object in destX and destY. Mode CURRENT_POSITION will take the object's current position. Mode TEMPLATE_POSITION will take the object's template position.
.macro getobjectxy localId:req, posType:req, destX:req, destY:req
callnative ScrCmd_getobjectxy
.2byte \localId
.2byte \posType
.2byte \destX
.2byte \destY
.endm
.macro getobjecttemplatexy localId:req, posType = TEMPLATE_POSITION, destX:req, destY:req
callnative ScrCmd_getobjectxy
.2byte \localId
.2byte \posType
.2byte \destX
.2byte \destY
.endm
.macro getobjectcurrentxy localId:req, posType = CURRENT_POSITION, destX:req, destY:req
callnative ScrCmd_getobjectxy
.2byte \localId
.2byte \posType
.2byte \destX
.2byte \destY
.endm
@ Return TRUE to dest if there is an object at the position x and y.
.macro checkobjectat x:req, y:req, dest = VAR_RESULT
callnative ScrCmd_checkobjectat
.2byte \x
.2byte \y
.2byte \dest
.endm
@ Returns the state of the Pokedex Seen Flag to VAR_RESULT for the Pokemon with speciesId
.macro getseenmon species:req
callnative Scrcmd_getsetpokedexflag
.2byte \species
.2byte FLAG_GET_SEEN
.endm
@ Returns the state of the Pokedex Caught Flag to VAR_RESULT for the Pokemon with speciesId
.macro getcaughtmon species:req
callnative Scrcmd_getsetpokedexflag
.2byte \species
.2byte FLAG_GET_CAUGHT
.endm
@ Sets the Pokedex Seen Flag for the Pokemon with speciesId
.macro setseenmon species:req
callnative Scrcmd_getsetpokedexflag
.2byte \species
.2byte FLAG_SET_SEEN
.endm
@ Sets the Pokedex Caught Flag for the Pokemon with speciesId
.macro setcaughtmon species:req
callnative Scrcmd_getsetpokedexflag
.2byte \species
.2byte FLAG_SET_CAUGHT
.endm
@ Check if the Player has speciesId in their party. OPEN_PARTY_SCREEN will have the player select a mon from their party. NO_PARTY_SCREEN will automatically check every mon in the player's party.
.macro checkspecies speciesId:req, mode=NO_PARTY_SCREEN
.if \mode == OPEN_PARTY_SCREEN
special ChoosePartyMon
waitstate
callnative Scrcmd_checkspecies_choose
.2byte \speciesId
.else
callnative Scrcmd_checkspecies
.2byte \speciesId
.endif
.endm
.macro checkspecies_choose speciesId:req
checkspecies \speciesId, OPEN_PARTY_SCREEN
.endm
@ Gets the facing direction of a given event object and stores it in the variable dest.
.macro getobjectfacingdirection localId:req, dest:req
callnative Scrcmd_getobjectfacingdirection
.2byte \localId
.2byte \dest
.endm

View File

@ -934,6 +934,44 @@ gBattleAnimMove_ToxicSpikes::
end
gBattleAnimMove_HeartSwap::
loadspritegfx ANIM_TAG_RED_HEART
loadspritegfx ANIM_TAG_PINKVIO_ORB
loadspritegfx ANIM_TAG_SPARKLE_2
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_BG, 3, 0, 8, RGB(31, 24, 26)
createvisualtask AnimTask_HeartSwap, 3, ANIM_TARGET
createvisualtask AnimTask_BlendMonInAndOut, 5, ANIM_TARGET, RGB_WHITE, 12, 3, 1
loopsewithpan SE_M_TAIL_WHIP, SOUND_PAN_ATTACKER, 10, 8
delay 16
createvisualtask AnimTask_HeartSwap, 3, ANIM_ATTACKER
createvisualtask AnimTask_BlendMonInAndOut, 5, ANIM_ATTACKER, RGB_WHITE, 12, 3, 1
waitforvisualfinish
createsprite gGrantingStarsSpriteTemplate, ANIM_ATTACKER, 2, -15, 0, 0, 0, 32, 60
createsprite gGrantingStarsSpriteTemplate, ANIM_TARGET, 2, -15, 0, 0, 0, 32, 60
delay 8
createsprite gGrantingStarsSpriteTemplate, ANIM_ATTACKER, 2, 12, -5, 0, 0, 32, 60
createsprite gGrantingStarsSpriteTemplate, ANIM_TARGET, 2, 12, -5, 0, 0, 32, 60
delay 4
playsewithpan SE_SHINY, SOUND_PAN_ATTACKER
createvisualtask AnimTask_BlendMonInAndOut, 5, ANIM_ATTACKER, RGB(31, 25, 27), 12, 3, 1
createvisualtask AnimTask_ScaleMonAndRestore, 5, -3, -3, 16, ANIM_ATTACKER, 0
createvisualtask AnimTask_BlendMonInAndOut, 5, ANIM_TARGET, RGB(31, 25, 27), 12, 3, 1
createvisualtask AnimTask_ScaleMonAndRestore, 5, -3, -3, 16, ANIM_TARGET, 0
createsprite gRedHeartBurstSpriteTemplate, ANIM_TARGET, 3, 160, -32
createsprite gRedHeartBurstSpriteTemplate, ANIM_TARGET, 3, -256, -40
createsprite gRedHeartBurstSpriteTemplate, ANIM_TARGET, 3, 128, -16
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_BG, 3, 8, 0, RGB(31, 24, 26)
createsprite gRedHeartCharmSpriteTemplate, ANIM_ATTACKER, 3, 0, 20
playsewithpan SE_M_MORNING_SUN, SOUND_PAN_ATTACKER
delay 15
createsprite gRedHeartCharmSpriteTemplate, ANIM_ATTACKER, 3, -20, 20
playsewithpan SE_M_CHARM, SOUND_PAN_ATTACKER
delay 15
createsprite gRedHeartCharmSpriteTemplate, ANIM_ATTACKER, 3, 20, 20
playsewithpan SE_M_CHARM, SOUND_PAN_ATTACKER
waitforvisualfinish
clearmonbg ANIM_ATTACKER
clearmonbg ANIM_TARGET
blendoff
end
gBattleAnimMove_AquaRing::
@ -7672,6 +7710,17 @@ gBattleAnimMove_NobleRoar::
end
gBattleAnimMove_IonDeluge::
loadspritegfx ANIM_TAG_IONS
loopsewithpan SE_M_THUNDERBOLT2, SOUND_PAN_ATTACKER, 10, 12
createvisualtask AnimTask_BlendBattleAnimPal, 10, (F_PAL_BG | F_PAL_BATTLERS_2), 2, 0, 4, RGB_YELLOW
waitforvisualfinish
createvisualtask AnimTask_CreateIons, 2, 0, 3, 120
createvisualtask AnimTask_CreateIons, 2, 0, 3, 120
delay 120
delay 30
waitforvisualfinish
createvisualtask AnimTask_BlendBattleAnimPal, 10, (F_PAL_BG | F_PAL_BATTLERS_2), 2, 4, 0, RGB_YELLOW
waitforvisualfinish
end
gBattleAnimMove_ParabolicCharge::

View File

@ -214,27 +214,25 @@ BattleScript_EffectDoodle::
attackcanceler
attackstring
ppreduce
trycopyability BS_ATTACKER, BattleScript_ButItFailed
attackanimation
waitanimation
setbyte gBattleCommunication, 0
goto BattleScript_EffectDoodle_AfterCopy
BattleScript_EffectDoodle_CopyAbility:
trycopyability BS_ATTACKER, BattleScript_ButItFailed
trycopyability BS_ATTACKER, BattleScript_MoveEnd
BattleScript_EffectDoodle_AfterCopy:
.if B_ABILITY_POP_UP == TRUE
setbyte sFIXED_ABILITY_POPUP, TRUE
showabilitypopup BS_ATTACKER
pause 60
sethword sABILITY_OVERWRITE, 0
updateabilitypopup BS_ATTACKER
pause 20
destroyabilitypopup
pause 40
copybyte gBattlerAbility, gBattlerAttacker
call BattleScript_AbilityPopUpOverwriteThenNormal
.endif
recordability BS_ATTACKER
printstring STRINGID_PKMNCOPIEDFOE
waitmessage B_WAIT_TIME_LONG
switchinabilities BS_ATTACKER
jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0x0, BattleScript_MoveEnd
addbyte gBattleCommunication, 1
jumpifnoally BS_TARGET, BattleScript_MoveEnd
jumpifnoally BS_ATTACKER, BattleScript_MoveEnd
setallytonextattacker BattleScript_EffectDoodle_CopyAbility
goto BattleScript_MoveEnd
@ -2346,6 +2344,11 @@ BattleScript_EffectSimpleBeam::
setabilitysimple BS_TARGET, BattleScript_ButItFailed
attackanimation
waitanimation
.if B_ABILITY_POP_UP == TRUE
copybyte gBattlerAbility, gBattlerTarget
call BattleScript_AbilityPopUpOverwriteThenNormal
.endif
recordability BS_TARGET
printstring STRINGID_PKMNACQUIREDSIMPLE
waitmessage B_WAIT_TIME_LONG
trytoclearprimalweather
@ -2444,11 +2447,17 @@ BattleScript_EffectWorrySeed::
tryworryseed BattleScript_ButItFailed
attackanimation
waitanimation
.if B_ABILITY_POP_UP == TRUE
copybyte gBattlerAbility, gBattlerTarget
call BattleScript_AbilityPopUpOverwriteThenNormal
.endif
recordability BS_TARGET
printstring STRINGID_PKMNACQUIREDABILITY
waitmessage B_WAIT_TIME_LONG
trytoclearprimalweather
tryrevertweatherform
flushtextbox
tryendneutralizinggas BS_TARGET
goto BattleScript_MoveEnd
BattleScript_EffectPowerSplit::
@ -5038,15 +5047,10 @@ BattleScript_EffectRolePlay::
attackanimation
waitanimation
.if B_ABILITY_POP_UP == TRUE
setbyte sFIXED_ABILITY_POPUP, TRUE
showabilitypopup BS_ATTACKER
pause 60
sethword sABILITY_OVERWRITE, 0
updateabilitypopup BS_ATTACKER
pause 20
destroyabilitypopup
pause 40
copybyte gBattlerAbility, gBattlerAttacker
call BattleScript_AbilityPopUpOverwriteThenNormal
.endif
recordability BS_ATTACKER
printstring STRINGID_PKMNCOPIEDFOE
waitmessage B_WAIT_TIME_LONG
switchinabilities BS_ATTACKER
@ -5189,12 +5193,17 @@ BattleScript_EffectSkillSwap::
tryswapabilities BattleScript_ButItFailed
attackanimation
waitanimation
jumpiftargetally BattleScript_EffectSkillSwap_AfterAbilityPopUp
.if B_ABILITY_POP_UP == TRUE
call BattleScript_AbilityPopUpTarget
pause 20
copybyte gBattlerAbility, gBattlerAttacker
call BattleScript_AbilityPopUp
call BattleScript_AbilityPopUpOverwriteThenNormal
copybyte gBattlerAbility, gBattlerTarget
copyhword sABILITY_OVERWRITE, gLastUsedAbility
call BattleScript_AbilityPopUpOverwriteThenNormal
.endif
BattleScript_EffectSkillSwap_AfterAbilityPopUp:
recordability BS_ATTACKER
recordability BS_TARGET
printstring STRINGID_PKMNSWAPPEDABILITIES
waitmessage B_WAIT_TIME_LONG
.if B_SKILL_SWAP >= GEN_4
@ -7612,6 +7621,18 @@ BattleScript_AbilityPopUpScripting:
sethword sABILITY_OVERWRITE, 0
return
BattleScript_AbilityPopUpOverwriteThenNormal:
setbyte sFIXED_ABILITY_POPUP, TRUE
showabilitypopup BS_ABILITY_BATTLER
pause 60
sethword sABILITY_OVERWRITE, 0
updateabilitypopup BS_ABILITY_BATTLER
pause 20
recordability BS_ABILITY_BATTLER
destroyabilitypopup
pause 40
return
BattleScript_SpeedBoostActivates::
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_SpeedBoostActivatesEnd
call BattleScript_AbilityPopUp
@ -8414,33 +8435,30 @@ BattleScript_CursedBodyActivates::
return
BattleScript_MummyActivates::
call BattleScript_AbilityPopUp
.if B_ABILITY_POP_UP == TRUE
call BattleScript_AbilityPopUpTarget
setbyte sFIXED_ABILITY_POPUP, TRUE
copybyte gBattlerAbility, gBattlerAttacker
copyhword sABILITY_OVERWRITE, gLastUsedAbility
call BattleScript_AbilityPopUpOverwriteThenNormal
.endif
recordability BS_TARGET
recordability BS_ATTACKER
printstring STRINGID_ATTACKERACQUIREDABILITY
waitmessage B_WAIT_TIME_LONG
return
BattleScript_WanderingSpiritActivates::
.if B_ABILITY_POP_UP == TRUE
setbyte sFIXED_ABILITY_POPUP, TRUE
copybyte gBattlerAbility, gBattlerTarget
sethword sABILITY_OVERWRITE, ABILITY_WANDERING_SPIRIT
showabilitypopup BS_TARGET
pause 60
sethword sABILITY_OVERWRITE, 0
updateabilitypopup BS_TARGET
pause 20
destroyabilitypopup
pause 40
call BattleScript_AbilityPopUpOverwriteThenNormal
copybyte gBattlerAbility, gBattlerAttacker
setbyte sFIXED_ABILITY_POPUP, TRUE
copyhword sABILITY_OVERWRITE, gLastUsedAbility
showabilitypopup BS_ATTACKER
pause 60
sethword sABILITY_OVERWRITE, 0
updateabilitypopup BS_ATTACKER
pause 20
destroyabilitypopup
pause 40
call BattleScript_AbilityPopUpOverwriteThenNormal
.endif
recordability BS_TARGET
recordability BS_ATTACKER
printstring STRINGID_SWAPPEDABILITIES
waitmessage B_WAIT_TIME_LONG
switchinabilities BS_ATTACKER

View File

@ -42,6 +42,7 @@
#include "constants/metatile_labels.h"
#include "constants/moves.h"
#include "constants/party_menu.h"
#include "constants/pokedex.h"
#include "constants/pokemon.h"
#include "constants/roulette.h"
#include "constants/script_menu.h"

View File

@ -1258,7 +1258,11 @@ EventScript_CloseMossdeepGameCornerBarrier::
CableClub_OnResume:
special InitUnionRoom
.if OW_FLAG_MOVE_UNION_ROOM_CHECK != 0
return
.else
end
.endif
MossdeepCity_GameCorner_1F_EventScript_InfoMan2::
lock

View File

@ -368,6 +368,23 @@ EventScript_EndSurface::
releaseall
end
EventScript_DigCommon:
isfollowerfieldmoveuser VAR_0x8004
setfieldeffectargument 3, VAR_0x8004 @ skip pose if true
dofieldeffect FLDEFF_USE_DIG
waitstate
EventScript_DigSealedChamber:: @ fallthrough
setflag FLAG_SAFE_FOLLOWER_MOVEMENT
call_if_eq VAR_0x8004, TRUE, EventScript_FollowerFieldMove
callnative DoBrailleDigEffect
releaseall
end
@ Use Dig from party menu
EventScript_UseDig::
lockall
goto EventScript_DigCommon
Text_CantDive:
.string "The sea is deep here. A POKéMON\n"
.string "may be able to go underwater.$"

View File

@ -36,6 +36,11 @@ EventScript_PkmnCenterNurse_TakeAndHealPkmn::
applymovement VAR_0x800B, Movement_PkmnCenterNurse_Turn @ Changed from Common_Movement_WalkInPlaceFasterLeft to force the follower to enter their Poké Ball
waitmovement 0
dofieldeffect FLDEFF_POKECENTER_HEAL
.if OW_UNION_DISABLE_CHECK == FALSE && OW_FLAG_MOVE_UNION_ROOM_CHECK != 0
setflag OW_FLAG_MOVE_UNION_ROOM_CHECK
call CableClub_OnResume
clearflag OW_FLAG_MOVE_UNION_ROOM_CHECK
.endif
waitfieldeffect FLDEFF_POKECENTER_HEAL
applymovement VAR_0x800B, Common_Movement_WalkInPlaceFasterDown
waitmovement 0

View File

@ -5,20 +5,21 @@
- [Setting up WSL1 (Legacy Portion)](./legacy_WSL1_INSTALL.md)
- [Run documentation site locally](local_mdbook/index.md)
- [Ubuntu WSL1/WSL2](local_mdbook/ubuntu_WSL.md)
- [AI Flags](./ai_flags.md)
- [Tutorials]()
- [How to add new AI Flags](./ai_logic.md)
- [How to add new battle script commands/macros](./how_to_battle_script_command_macro.md)
- [How to add a new move](./how_to_new_move.md)
- [How to add a new trainer class](./how_to_trainer_class.md)
- [What are AI Flags?](tutorials/ai_flags.md)
- [How to add new AI Flags](tutorials/ai_logic.md)
- [How to add new battle script commands/macros](tutorials/how_to_battle_script_command_macro.md)
- [How to add a new move](tutorials/how_to_new_move.md)
- [How to add a new trainer class](tutorials/how_to_trainer_class.md)
- [How to add a new Pokémon]()
- [v1.9.x](./how_to_new_pokemon_1_9_0.md)
- [v1.8.x](./how_to_new_pokemon_1_8_0.md)
- [v1.7.x](./how_to_new_pokemon_1_7_0.md)
- [v1.6.x](./how_to_new_pokemon_1_6_0.md)
- [How to use the Testing System](./how_to_testing_system.md)
- [v1.9.x](tutorials/how_to_new_pokemon_1_9_0.md)
- [v1.8.x](tutorials/how_to_new_pokemon_1_8_0.md)
- [v1.7.x](tutorials/how_to_new_pokemon_1_7_0.md)
- [v1.6.x](tutorials/how_to_new_pokemon_1_6_0.md)
- [How to use the Testing System](tutorials/how_to_testing_system.md)
- [Changelog](./CHANGELOG.md)
- [1.9.x]()
- [Version 1.9.3](changelogs/1.9.x/1.9.3.md)
- [Version 1.9.2](changelogs/1.9.x/1.9.2.md)
- [Version 1.9.1](changelogs/1.9.x/1.9.1.md)
- [Version 1.9.0](changelogs/1.9.x/1.9.0.md)
@ -30,43 +31,36 @@
- [Version 1.8.2](changelogs/1.8.x/1.8.2.md)
- [Version 1.8.1](changelogs/1.8.x/1.8.1.md)
- [Version 1.8.0](changelogs/1.8.x/1.8.0.md)
- [1.7.x]()
- [Version 1.7.4](changelogs/1.7.x/1.7.4.md)
- [Version 1.7.3](changelogs/1.7.x/1.7.3.md)
- [Version 1.7.2](changelogs/1.7.x/1.7.2.md)
- [Version 1.7.1](changelogs/1.7.x/1.7.1.md)
- [Version 1.7.0](changelogs/1.7.x/1.7.0.md)
- [1.6.x]()
- [Version 1.6.2](changelogs/1.6.x/1.6.2.md)
- [Version 1.6.1](changelogs/1.6.x/1.6.1.md)
- [Version 1.6.0](changelogs/1.6.x/1.6.0.md)
- [1.5.x]()
- [Version 1.5.3](changelogs/1.5.x/1.5.3.md)
- [Version 1.5.2](changelogs/1.5.x/1.5.2.md)
- [Version 1.5.1](changelogs/1.5.x/1.5.1.md)
- [Version 1.5.0](changelogs/1.5.x/1.5.0.md)
- [1.4.x]()
- [Version 1.4.3](changelogs/1.4.x/1.4.3.md)
- [Version 1.4.2](changelogs/1.4.x/1.4.2.md)
- [Version 1.4.1](changelogs/1.4.x/1.4.1.md)
- [Version 1.4.0](changelogs/1.4.x/1.4.0.md)
- [1.3.x]()
- [Version 1.3.0](changelogs/1.3.x/1.3.0.md)
- [1.2.x]()
- [Version 1.2.0](changelogs/1.2.x/1.2.0.md)
- [1.1.x]()
- [Version 1.1.1](changelogs/1.1.x/1.1.1.md)
- [Version 1.1.0](changelogs/1.1.x/1.1.0.md)
- [1.0.x]()
- [Version 1.0.0](changelogs/1.0.x/1.0.0.md)
- [Pre-1.0.x]()
- [Version 0.9.0](changelogs/0.9.x/0.9.0.md)
- [Team Procedures]()
- [How to make an Expansion version](team_procedures/expansion_versions.md)

View File

@ -0,0 +1,106 @@
# Version 1.9.3
```md
## How to update
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
- Once you have your remote set up, run the command `git pull RHH expansion/1.9.3`.
```
## 🌋 *REFACTORS* 🌋
📜 = Uses a migration script.
* Converted `settotemboost` command to `callnative` in [#5418](https://github.com/rh-hideout/pokeemerald-expansion/pull/5418)
* Removed unused `RESOURCE_FLAG_TRACED` in [#5430](https://github.com/rh-hideout/pokeemerald-expansion/pull/5430)
* Changed `MOVEEND_` defines to an enum in [#5449](https://github.com/rh-hideout/pokeemerald-expansion/pull/5449)
## ✨ Feature Branches ✨
### ***merrp/aarant's Followers***
#### Fixed
* Fixed Expansion-exclusive issue that caused trainers to not play their "pointing" animation when Followers were out during battle intro by @kittenchilly in [#5406](https://github.com/rh-hideout/pokeemerald-expansion/pull/5406)
## ⚔️ Battle General ⚔️ ##
### Changed
* Improved Mega evolution animation to make it a little smoother by @kleenxfeu in [#4816](https://github.com/rh-hideout/pokeemerald-expansion/pull/4816)
### Fixed
* Fixed affection check for exp multiplier by @Bassoonian in [#5421](https://github.com/rh-hideout/pokeemerald-expansion/pull/5421)
* Fixed multiple Primal Reversions not occurring if multiple battlers fainted on the previous turn by @PhallenTree in [#5430](https://github.com/rh-hideout/pokeemerald-expansion/pull/5430)
## 🤹 Moves 🤹
### Added
* Added missing `B_AFTER_YOU_TURN_ORDER` config by @PhallenTree in [#5400](https://github.com/rh-hideout/pokeemerald-expansion/pull/5400)
* Gen 5-7: After You fails if the order remains the same after using After You.
* Gen 8+: After You no longer fails if the turn order remains the same after using After You.
* Added missing `B_QUASH_TURN_ORDER` config by @PhallenTree in [#5400](https://github.com/rh-hideout/pokeemerald-expansion/pull/5400)
* Gen 5-7: If multiple Pokémon are affected by Quash, they move in the order they were affected by Quash.
* Gen 8+: If multiple Pokémon are affected by Quash, they now move fastest to slowest.
* Added missing updated `B_UPDATED_CONVERSION_2` by @wiz1989 in [#5453](https://github.com/rh-hideout/pokeemerald-expansion/pull/5453)
* Gens 2-4: Conversion 2 changes the user's type to a type that is resistant/immune to the last move the user was hit by.
* Gen 5+: Conversion 2 changes the user's type to a type that resists the last move used by the selected target.
### Fixed
* Fixed Scale Shot corrupting the move used on the next turn by @AlexOn1ine in [#5397](https://github.com/rh-hideout/pokeemerald-expansion/pull/5397)
* Fixed Growth's description not being updated based on `B_GROWTH_STAT_RAISE` by @nescioquid in [#5398](https://github.com/rh-hideout/pokeemerald-expansion/pull/5398)
* Fixed Quash not updating the battlers' actions correctly by @PhallenTree in [#5400](https://github.com/rh-hideout/pokeemerald-expansion/pull/5400)
* Cleanup by @PhallenTree in [#5430](https://github.com/rh-hideout/pokeemerald-expansion/pull/5430)
* Fixed Snatched Swallow not recovering HP if the Snatcher is not under the effect of Stockpile (should still heal) by @PhallenTree in [#5430](https://github.com/rh-hideout/pokeemerald-expansion/pull/5430)
* Fixed Counter users being damaged by Spiky Shield by @AlexOn1ine in [#5402](https://github.com/rh-hideout/pokeemerald-expansion/pull/5402)
* Fixed Electrified Dragon Darts not correctly avoiding targets with ability immunity (Volt Absorb, Motor Drive) by @PhallenTree in [#5430](https://github.com/rh-hideout/pokeemerald-expansion/pull/5430)
* Fixed Trace not activating a switch-in ability it traces (eg. Intimidate) by @PhallenTree in [#5430](https://github.com/rh-hideout/pokeemerald-expansion/pull/5430)
* Removed unused `RESOURCE_FLAG_TRACED`.
* Fixed recoil damage not triggering healing berries by @AlexOn1ine in [#5449](https://github.com/rh-hideout/pokeemerald-expansion/pull/5449)
* Also changed `MOVEEND_` defines to an enum.
## 🎭 Abilities 🎭
### Fixed
* Fixed Dancer activating even if the dance move is stolen by Snatch by @PhallenTree in [#5430](https://github.com/rh-hideout/pokeemerald-expansion/pull/5430)
* Fixed Ability popup when multiple Pokémon faint at the same time by @PhallenTree in [#5430](https://github.com/rh-hideout/pokeemerald-expansion/pull/5430)
* Multiple ability fixes by @PhallenTree in [#5447](https://github.com/rh-hideout/pokeemerald-expansion/pull/5447)
* Fixed Protosynthesis/Quark Drive sometimes not activating ability popup despite still gaining the boost as they should.
* Fixed Protosynthesis/Quark Drive activating on Transformed battlers.
* Fixed Protosynthesis activating despite Cloud Nine being present on the field.
* Fixed Quark Drive not activating if the battler is not grounded.
* Fixed Protosynthesis/Quark Drive/Beast Boost stat raise priority when multiple stats are tied for the highest one.
* Before: `Attack, Defense, Speed, Special Attack, Special Defense`.
* After: `Attack, Defense, Special Attack, Special Defense, Speed`.
## 🧶 Items 🧶
### Fixed
* Fixed Ogerpon's Masks not increasing the power of moves by 20% by @AlexOn1ine in [#5391](https://github.com/rh-hideout/pokeemerald-expansion/pull/5391)
* Fixed Jubilife Muffin not working by @kittenchilly in [#5444](https://github.com/rh-hideout/pokeemerald-expansion/pull/5444)
* Fixed duplicating flute bug in double battles by @ghoulslash in [#5436](https://github.com/rh-hideout/pokeemerald-expansion/pull/5436)
## 🤖 Battle AI 🤖
### Fixed
* Fixed Trick/Switcheroo giving AI score even if the opponent has no held item by @kittenchilly in [#5412](https://github.com/rh-hideout/pokeemerald-expansion/pull/5412)
* Various AI fixes in `AI_CalcMoveEffectScore` by @ghoulslash in [#5474](https://github.com/rh-hideout/pokeemerald-expansion/pull/5474)
* Missing break from `EFFECT_ABSORB` switch case.
* Using last used move for Mirror Move instead of predicted move.
## 🧹 Other Cleanup 🧹
### Changed
* Converted `settotemboost` command to `callnative` by @ghoulslash in [#5418](https://github.com/rh-hideout/pokeemerald-expansion/pull/5418)
* Removed trailing whitespace by @kittenchilly in [#5455](https://github.com/rh-hideout/pokeemerald-expansion/pull/5455)
* Removed binary match workaround for Rayquaza's tail in Sootopolis' cutscene by @hedara90 in https://github.com/rh-hideout/pokeemerald-expansion/pull/5480
### Fixed
* Fixed potential uninitialized behavior in `ChangeOrderTargetAfterAttacker` by @AlexOn1ine in [#5393](https://github.com/rh-hideout/pokeemerald-expansion/pull/5393)
* Fallback on default BW map pop-up theme to reduce potential for error by @ravepossum in [#5392](https://github.com/rh-hideout/pokeemerald-expansion/pull/5392)
* Multiple typo fixes by @nescioquid in [#5398](https://github.com/rh-hideout/pokeemerald-expansion/pull/5398)
* VS Seeker documentation fix by @Bassoonian in [#5415](https://github.com/rh-hideout/pokeemerald-expansion/pull/5415)
## 🧪 Test Runner 🧪
### Added
* Added missing After You and Quash tests by @PhallenTree in [#5400](https://github.com/rh-hideout/pokeemerald-expansion/pull/5400)
### Changed
* Improved Tangling Hair test to make sure that chained effects do not overwrite relevant battler IDs by @ghoulslash in [#5423](https://github.com/rh-hideout/pokeemerald-expansion/pull/5423)
* Improved Full Heal item tests by @kittenchilly in [#5444](https://github.com/rh-hideout/pokeemerald-expansion/pull/5444)
### Fixed
* Fixed Wake-Up Slap test typo by @Pawkkie in [#5442](https://github.com/rh-hideout/pokeemerald-expansion/pull/5442)
* Fixed test assumption fail summary fields using more memory than needed by @AsparagusEduardo in [#5443](https://github.com/rh-hideout/pokeemerald-expansion/pull/5443)
* Fixed issue with `PASSES_RANDOMLY` in AI tests by @Pawkkie in https://github.com/rh-hideout/pokeemerald-expansion/pull/5486
## New Contributors
* @nescioquid made their first contribution in [#5398](https://github.com/rh-hideout/pokeemerald-expansion/pull/5398)
* @kleenxfeu made their first contribution in [#4816](https://github.com/rh-hideout/pokeemerald-expansion/pull/4816)
* @wiz1989 made their first contribution in [#5453](https://github.com/rh-hideout/pokeemerald-expansion/pull/5453)
**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.9.2...expansion/1.9.3
<!--Last PR: 5486-->
<!--Used to keep track of the last PR merged in case new ones come in before the changelog is done.-->

View File

@ -0,0 +1,187 @@
# How to make an Expansion version
*If you need instructions on how to release a new Expansion version, check out the enclosed instruction book. - AsparagusEduardo*
## 1.- Autogenerating a changelog for the `master` branch.
*Requires Write access to the repo.*
If the changelog you're making is for a minor version (Eg. 1.3.0), make sure to sync the `upcoming` branch with `master` before starting. Keep in mind that if there are unreleased changes in `master`, they should be made into a patch version released alongside minor version.
- Go to https://github.com/rh-hideout/pokeemerald-expansion/releases.
- Press the option "Draft a new release".
- Fill the following fields:
- In "Choose a tag", write the name of the tag for the desired release number.
- Eg. for version 1.2.3, write `expansion/1.2.3`. ***It cannot be an existing tag.***
- In "Target" choose `master`.
- In "Previous tag", select the latest version released.
- Press "Generate release notes". This will fill the description with a list of PRs made to the `master` branch since the lastest release.
- You may copy the contents to your editor of choice for step 2.
- If the changelog you're making is for a minor version (Eg. 1.3.0), proceed to step 1B, without closing the current window.
## 1B.- Autogenerating a changelog for the `upcoming` branch.
- Delete the text and title generated in the site.
- Change "Target" to `upcoming`.
- Press "Generate release notes". This will autogenerate the description with changes from both branches, as they've been merged.
- Use a comparison tool to remove any shared PRs from `master`. (I use [WinMerge](https://winmerge.org/) for this).
- Also remove any shared "New Contributor" entries.
- You should now have a text that only contains PRs made to `upcoming`.
## 2.- Sorting PRs in the changelog
- Copy the `docs/changelogs/template.md` file into a new file with the corresponding version for file and folder. Eg, for 1.2.3, you copy the file into `docs/changelogs/1.2.x/1.2.3.md`.
- Use the following Regex to adapt all PR links into the format currently used:
- Search
```
in https://github\.com/rh-hideout/pokeemerald-expansion/pull/(\d+)
```
- Replace
```
in [#$1](https://github.com/rh-hideout/pokeemerald-expansion/pull/$1)
```
- At the bottom of the template, replace the "____" in `<!--Last PR: ____-->` with the number of the last PR in your autogenerated changelog. This will help you keep track of any new PRs that are merged in before you're finished with your changelog.
- Sort the PRs by the categories present in the PR taking the following considerations:
- Keep the language of the changelog as newbie friendly as possible, explaining how the PR affects them.
- The format of the main line is the following:
```
{{Description of the change}} by @{{GitHub user}} in {{PR link}}
```
- If a PR reverted by a different PR, both should be removed.
- If the reverted PR's contents are then re-added it should be treated as if it's the first time added, with all the proper documentation needed.
- If a PR's content fits into multiple categories, like fixing two unrelated Ability and Move effects, you may duplicate the PR line and put it in both categories, changing the description of it accordingly.
- When refering to an element present in the code, always enclose them with ` to easily tell them apart. Eg:
- "Converted `settotemboost` command to `callnative`"
- "Changed `MOVEEND_` defines to an enum"
- A PR's technical changes that may conflict with user changes should have an entry in the "**REFACTORS**" section at the beginning of the changelog. Any of these changes that requires a migration script should also be marked as such by appending the corresponding emoji listed there. The section should include, but it's not limited to:
- Massive data format and/or structuring changes.
- Converting defines to enums.
- Renaming structs and/or their fields.
- Removing enums/defines/structs.
- For fixes:
- Once on their respective categories, if a PR fixes multiple issues at once in that category, you may make a sublist of those issues to properly detail each one and avoid just writing "Fixed multiple ability issues" or an overly verbose sentence for the PR.
- Try to fit the contents of a PR as a single sentence in past tense that.
- ***DON'T*** write something like "Fixed Parental Bond", as this doesn't explain *what* was fixed in Parental Bond. Instead, write something like "Fixed Parental Bond not affecting Snore".
- For new configs:
- Add the name of the config as part of the sentence, with subitems explaining what they do based on their generation if it's a generational config. Eg:
```
* Added missing `B_AFTER_YOU_TURN_ORDER` config by @PhallenTree in [#5400](https://github.com/rh-hideout/pokeemerald-expansion/pull/5400)
* Gen 5-7: After You fails if the order remains the same after using After You.
* Gen 8+: After You no longer fails if the turn order remains the same after using After You.
```
- For other new features:
- Explain how to use the feature completely, listing all its features as needed. For now, this is the only source of documentation for these features, so it's important to be thorough.
# 3.- Preparing the code for the new version
- Search for all non-changelog instances of the previous released version and update them to the newer version. As of writing, it's these files:
- `README.md`:
```diff
-Based off RHH's pokeemerald-expansion 1.2.2 https://github.com/rh-hideout/pokeemerald-expansion/
+Based off RHH's pokeemerald-expansion 1.2.3 https://github.com/rh-hideout/pokeemerald-expansion/
```
```diff
-- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.2.2, use `git pull RHH expansion/1.2.2`).
+- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.2.3, use `git pull RHH expansion/1.2.3`).
```
- `.github/ISSUE_TEMPLATE/*.yaml`
- Patch version:
```diff
options:
- 1.2.2 (Latest release)
+ 1.2.3 (Latest release)
master (default, unreleased bugfixes)
upcoming (Edge)
+ 1.2.2
1.2.1
1.2.0
```
- Minor Version:
```diff
options:
- 1.2.2 (Latest release)
+ 1.2.3 (Latest release)
master (default, unreleased bugfixes)
upcoming (Edge)
+ 1.2.2
1.2.1
1.2.0
- 1.1.6
- 1.1.5
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.1
- 1.1.0
- pre-1.1.0
+ pre-1.2.0
```
- `docs/SUMMARY.md`:
- Patch version:
```diff
[Changelog](./CHANGELOG.md)
- [1.2.x]()
+ - [Version 1.2.3](changelogs/1.2.x/1.2.3.md)
- [Version 1.2.2](changelogs/1.2.x/1.2.2.md)
- [Version 1.2.1](changelogs/1.2.x/1.2.1.md)
- [Version 1.2.0](changelogs/1.2.x/1.2.0.md)
```
- Minor version:
```diff
[Changelog](./CHANGELOG.md)
+ - [1.3.x]()
+ - [Version 1.3.0](changelogs/1.3.x/1.3.0.md)
- [1.2.x]()
- [Version 1.2.2](changelogs/1.2.x/1.2.2.md)
- [Version 1.2.1](changelogs/1.2.x/1.2.1.md)
- [Version 1.2.0](changelogs/1.2.x/1.2.0.md)
```
- `include/constants/expansion.h`:
- The defines should already have the version we're targetting as part of the previous changelog process.
```diff
-// Last version: 1.2.2
+// Last version: 1.2.3
#define EXPANSION_VERSION_MAJOR 1
#define EXPANSION_VERSION_MINOR 2
#define EXPANSION_VERSION_PATCH 3
// FALSE if this this version of Expansion is not a tagged commit, i.e.
// it contains unreleased changes.
-#define EXPANSION_TAGGED_RELEASE FALSE
+#define EXPANSION_TAGGED_RELEASE TRUE
```
# 4.- Make a PR with the changes listed in Steps 2/3.
- Also post the changelog for feedback from contributors and maintainers.
- Once all feedback has been addresses, you may merge.
# 5.- Create the release on GitHub
- Copy the contents of your manual changelog into the description of your release.
- Modify the title to "Version {{version}}", eg. "Version 1.2.3"
- Be sure to have the "Set as the latest release" option set,
- Press "Publish Release".
- This will create a new tag in the repo that users can pull from like they can with branches.
# 6.- Post-release handling
- ***DON'T ACCEPT ANY NEW PRs YET.*** We have to prepare for the next cycle first.
- Go to `include/constants/expansion.h` and merge the following changes to the repo (PR or direct commit, doesn't matter much):
- Patch version:
```diff
// Last version: 1.2.3
#define EXPANSION_VERSION_MAJOR 1
#define EXPANSION_VERSION_MINOR 2
- #define EXPANSION_VERSION_PATCH 3
+ #define EXPANSION_VERSION_PATCH 4
// FALSE if this this version of Expansion is not a tagged commit, i.e.
// it contains unreleased changes.
-#define EXPANSION_TAGGED_RELEASE TRUE
+#define EXPANSION_TAGGED_RELEASE FALSE
```
With this, the repo is ready again to receive new PRs.
# Now you're ready to make the announcements!
- We tend to post on the following Discord Servers:
- [RH-Hideout](https://discord.gg/6CzjAG6GZk)
- Requires role to post in #announcements channel.
- [Team Aqua's Hideout](https://discord.gg/team-aqua-s-hideout-976252009114140682)
- Requires role to post in #romhacking-updates channel.
- [What a Hack!](https://discord.gg/whack-a-hack-292436944670162955)
- Announcements are done in Spanish, but not the changelogs themselves.
- Requires role to ping "Decompilaciones" role.
- [pret](https://discord.gg/R4c3FA95dP)
- [PokéCommunity](https://discord.gg/pokecommunity)
You can make a highlight of changes in the announcement itself, but it's not needed. (I also like using Discord emotes to highlight certain features during announcements, but gain, it's not needed).

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 268 B

View File

@ -393,10 +393,6 @@ $(RAYQUAZAGFXDIR)/scene_2/bg.4bpp: %.4bpp: %.png
$(RAYQUAZAGFXDIR)/scene_3/rayquaza.4bpp: %.4bpp: %.png
$(GFX) $< $@ -num_tiles 124 -Wnum_tiles
$(RAYQUAZAGFXDIR)/scene_3/rayquaza_tail_fix.4bpp: $(RAYQUAZAGFXDIR)/scene_3/rayquaza_tail.4bpp
cp $< $@
head -c 12 /dev/zero >> $@
$(RAYQUAZAGFXDIR)/scene_4/streaks.4bpp: %.4bpp: %.png
$(GFX) $< $@ -num_tiles 19 -Wnum_tiles

View File

@ -378,6 +378,7 @@ struct AiLogicData
u8 ejectPackSwitch:1; // Tracks whether current switch out was from Eject Pack
u8 padding:5;
u8 shouldSwitch; // Stores result of ShouldSwitch, which decides whether a mon should be switched out
u8 aiCalcInProgress:1;
};
struct AI_ThinkingStruct
@ -716,7 +717,6 @@ struct BattleStruct
} multiBuffer;
u8 wishPerishSongState;
u8 wishPerishSongBattlerId;
u8 aiCalcInProgress:1;
u8 overworldWeatherDone:1;
u8 startingStatusDone:1;
u8 isAtkCancelerForCalledMove:1; // Certain cases in atk canceler should only be checked once, when the original move is called, however others need to be checked the twice.
@ -1094,6 +1094,7 @@ extern u16 gLastPrintedMoves[MAX_BATTLERS_COUNT];
extern u16 gLastMoves[MAX_BATTLERS_COUNT];
extern u16 gLastLandedMoves[MAX_BATTLERS_COUNT];
extern u16 gLastHitByType[MAX_BATTLERS_COUNT];
extern u16 gLastUsedMoveType[MAX_BATTLERS_COUNT];
extern u16 gLastResultingMoves[MAX_BATTLERS_COUNT];
extern u16 gLockedMoves[MAX_BATTLERS_COUNT];
extern u16 gLastUsedMove;

View File

@ -15,6 +15,13 @@ enum DamageRollType
DMG_ROLL_HIGHEST,
};
enum AIPivot
{
DONT_PIVOT,
CAN_TRY_PIVOT,
SHOULD_PIVOT,
};
bool32 AI_IsFaster(u32 battlerAi, u32 battlerDef, u32 move);
bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 move);
bool32 AI_RandLessThan(u32 val);
@ -52,8 +59,6 @@ bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move);
u32 AI_GetWeather(struct AiLogicData *aiData);
bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits);
bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, u32 numHits);
bool32 AI_IsTerrainAffected(u32 battlerId, u32 flags);
bool32 AI_IsBattlerGrounded(u32 battlerId);
bool32 HasDamagingMove(u32 battlerId);
bool32 HasDamagingMoveOfType(u32 battlerId, u32 type);
u32 GetBattlerSecondaryDamage(u32 battlerId);
@ -65,7 +70,7 @@ u32 GetBattlerSideSpeedAverage(u32 battler);
bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage);
bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent);
bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect);
bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex);
enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex);
bool32 IsRecycleEncouragedItem(u32 item);
bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item);
bool32 IsStatBoostingBerry(u32 item);
@ -80,7 +85,6 @@ bool32 AnyStatIsRaised(u32 battlerId);
bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat);
bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat);
bool32 AreBattlersStatsMaxed(u32 battler);
bool32 BattlerHasAnyStatRaised(u32 battlerId);
u32 CountPositiveStatStages(u32 battlerId);
u32 CountNegativeStatStages(u32 battlerId);
bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility);
@ -120,7 +124,6 @@ bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool
bool32 HasAnyKnownMove(u32 battlerId);
bool32 IsAromaVeilProtectedMove(u32 move);
bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect);
bool32 IsStatLoweringMoveEffect(u32 moveEffect);
bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility);
bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsHazardMoveEffect(u32 moveEffect);
@ -173,7 +176,6 @@ bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId);
#define IS_TARGETING_PARTNER(battlerAtk, battlerDef)((battlerAtk) == (battlerDef ^ BIT_FLANK))
u32 GetAllyChosenMove(u32 battlerId);
bool32 IsValidDoubleBattle(u32 battlerAtk);
bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef);
bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove);

View File

@ -346,7 +346,6 @@ extern const union AnimCmd *const gAnims_WaterPulseBubble[];
// battle_anim_flying.c
void DestroyAnimSpriteAfterTimer(struct Sprite *sprite);
void sub_810E2C8(struct Sprite *sprite);
void AnimAirWaveCrescent(struct Sprite *sprite);
void AnimFlyBallUp(struct Sprite *sprite);
void AnimFlyBallAttack(struct Sprite *sprite);

View File

@ -20,6 +20,23 @@
#define MOVE_LIMITATION_PLACEHOLDER (1 << 15)
#define MOVE_LIMITATIONS_ALL 0xFFFF
enum MoveBlocked
{
MOVE_BLOCKED_BY_NO_ABILITY,
MOVE_BLOCKED_BY_SOUNDPROOF_OR_BULLETPROOF,
MOVE_BLOCKED_BY_DAZZLING,
MOVE_BLOCKED_BY_PARTNER_DAZZLING,
MOVE_BLOCKED_BY_GOOD_AS_GOLD,
};
enum MoveAbsorbed
{
MOVE_ABSORBED_BY_NO_ABILITY,
MOVE_ABSORBED_BY_DRAIN_HP_ABILITY,
MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY,
MOVE_ABSORBED_BY_BOOST_FLASH_FIRE,
};
enum {
ABILITYEFFECT_ON_SWITCHIN,
ABILITYEFFECT_ENDTURN,
@ -161,6 +178,9 @@ void SetAtkCancellerForCalledMove(void);
u8 AtkCanceller_UnableToUseMove2(void);
bool32 HasNoMonsToSwitch(u32 battler, u8 r1, u8 r2);
bool32 TryChangeBattleWeather(u32 battler, u32 weatherEnumId, bool32 viaAbility);
u32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef);
u32 CanPartnerAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef);
u32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType);
u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg);
bool32 TryPrimalReversion(u32 battler);
bool32 IsNeutralizingGasOnField(void);

View File

@ -69,6 +69,7 @@
#define B_RECOIL_IF_MISS_DMG GEN_LATEST // In Gen5+, Jump Kick and High Jump Kick will always do half of the user's max HP when missing.
#define B_KLUTZ_FLING_INTERACTION GEN_LATEST // In Gen5+, Pokémon with the Klutz ability can't use Fling.
#define B_UPDATED_CONVERSION GEN_LATEST // In Gen6+, Conversion changes the user's type to match their first move's. Before, it would choose a move at random.
#define B_UPDATED_CONVERSION_2 GEN_LATEST // In Gen5+, Conversion 2 changes the user's type to a type that resists the last move used by the selected target. Before, it would consider the last move being successfully hit by. Additionally, Struggle is considered Normal type before Gen 5.
#define B_PP_REDUCED_BY_SPITE GEN_LATEST // In Gen4+, Spite reduces the foe's last move's PP by 4, instead of 2 to 5.
#define B_EXTRAPOLATED_MOVE_FLAGS TRUE // Adds move flags to moves that they don't officially have but would likely have if they were in the latest core series game.
@ -186,6 +187,7 @@
#define B_SMART_WILD_AI_FLAG 0 // If not 0, you can set this flag in a script to enable smart wild pokemon
#define B_FLAG_NO_BAG_USE 0 // If this flag is set, the ability to use the bag in battle is disabled.
#define B_FLAG_NO_CATCHING 0 // If this flag is set, the ability to catch wild Pokémon is disabled.
#define B_FLAG_NO_RUNNING 0 // If this flag is set, the ability to escape from wild battles is disabled. Also makes Roar/Whirlwind and Teleport (under Gen8) fail.
#define B_FLAG_AI_VS_AI_BATTLE 0 // If this flag is set, the player's mons will be controlled by the ai next battles.
#define B_FLAG_DYNAMAX_BATTLE 0 // If this flag is set, the ability to Dynamax in battle is enabled for all trainers.
#define B_FLAG_TERA_ORB_CHARGED 0 // If this flag is set, the Tera Orb is charged. It is automatically set upon healing and cleared upon Terastallizing once configured.

View File

@ -106,6 +106,8 @@
#define OW_POPUP_BW_ALPHA_BLEND FALSE // Enables alpha blending/transparency for the pop-ups. Mainly intended to be used with the black color option.
// Pokémon Center
#define OW_IGNORE_EGGS_ON_HEAL GEN_LATEST // In Gen 4+, the nurse in the Pokémon Center does not heal Eggs on healing machine.
#define OW_IGNORE_EGGS_ON_HEAL GEN_LATEST // In Gen 4+, the nurse in the Pokémon Center does not heal Eggs on healing machine.
#define OW_UNION_DISABLE_CHECK FALSE // When TRUE, the nurse does not inform the player if there is a trainer waiting in the Union Room. This speeds up the loading of the Pokémon Center.
#define OW_FLAG_MOVE_UNION_ROOM_CHECK 0 // If this flag is set, the game will only check if players are in the Union Room while healing Pokémon, and not when players enter the Pokémon Center. This speeds up the loading of the Pokémon Center. This is ignored if OW_UNION_DISABLE_CHECK is TRUE.
#endif // GUARD_CONFIG_OVERWORLD_H

View File

@ -22,15 +22,16 @@
#define P_FRIENDSHIP_EVO_THRESHOLD GEN_LATEST // Since Gen 8, Pokémon that evolve by friendship evolve at or above 160 friendship instead of 220.
// Breeding settings
#define P_NIDORAN_M_DITTO_BREED GEN_LATEST // Since Gen 5, when Nidoran♂ breeds with Ditto it can produce Nidoran♀ offspring. Before, it would only yield male offspring. This change also applies to Volbeat.
#define P_INCENSE_BREEDING GEN_LATEST // Since Gen 9, cross-generation Baby Pokémon don't require Incense being held by the parents to be obtained via breeding.
#define P_EGG_HATCH_LEVEL GEN_LATEST // Since Gen 4, Pokémon will hatch from eggs at level 1 instead of 5.
#define P_BALL_INHERITING GEN_LATEST // Since Gen 6, Eggs from the Daycare will inherit the Poké Ball from their mother. From Gen 7 onwards, the father can pass it down as well, as long as it's of the same species as the mother.
#define P_TM_INHERITANCE GEN_LATEST // Since Gen 6, the father no longer passes down TMs to the baby.
#define P_MOTHER_EGG_MOVE_INHERITANCE GEN_LATEST // Since Gen 6, the mother can also pass down Egg Moves.
#define P_NATURE_INHERITANCE GEN_LATEST // In Gen 3, Everstone grants Ditto and mothers a 50% chance to pass on Nature. Since Gen 4, anyone can pass on nature. Since Gen 5, the chance is 100%.
#define P_ABILITY_INHERITANCE GEN_LATEST // In B2W2, a female Pokémon has an 80% chance of passing down their ability if bred with a male. Since Gen 6, the chance is 80% for normal ability and 60% for Hidden Ability, and anyone can pass down their abilities if bred with Ditto. NOTE: BW's effect: 60% chance to pass down HA and random for normal ability has been omitted.
#define P_EGG_MOVE_TRANSFER GEN_LATEST // Starting in Gen 8, if two Pokémon of the same species are together in the Daycare, one knows an Egg Move, and the other has an empty slot, the other Pokémon will receive the Egg Move in the empty slot. In Gen 9, if a Pokémon holds a Mirror Herb, it will receive Egg Moves from the other regardless of species.
#define P_NIDORAN_M_DITTO_BREED GEN_LATEST // Since Gen 5, when Nidoran♂ breeds with Ditto it can produce Nidoran♀ offspring. Before, it would only yield male offspring. This change also applies to Volbeat.
#define P_INCENSE_BREEDING GEN_LATEST // Since Gen 9, cross-generation Baby Pokémon don't require Incense being held by the parents to be obtained via breeding.
#define P_EGG_HATCH_LEVEL GEN_LATEST // Since Gen 4, Pokémon will hatch from eggs at level 1 instead of 5.
#define P_BALL_INHERITING GEN_LATEST // Since Gen 6, Eggs from the Daycare will inherit the Poké Ball from their mother. From Gen 7 onwards, the father can pass it down as well, as long as it's of the same species as the mother.
#define P_TM_INHERITANCE GEN_LATEST // Since Gen 6, the father no longer passes down TMs to the baby.
#define P_MOTHER_EGG_MOVE_INHERITANCE GEN_LATEST // Since Gen 6, the mother can also pass down Egg Moves.
#define P_NATURE_INHERITANCE GEN_LATEST // In Gen 3, Everstone grants Ditto and mothers a 50% chance to pass on Nature. Since Gen 4, anyone can pass on nature. Since Gen 5, the chance is 100%.
#define P_ABILITY_INHERITANCE GEN_LATEST // In B2W2, a female Pokémon has an 80% chance of passing down their ability if bred with a male. Since Gen 6, the chance is 80% for normal ability and 60% for Hidden Ability, and anyone can pass down their abilities if bred with Ditto. NOTE: BW's effect: 60% chance to pass down HA and random for normal ability has been omitted.
#define P_EGG_MOVE_TRANSFER GEN_LATEST // Starting in Gen 8, if two Pokémon of the same species are together in the Daycare, one knows an Egg Move, and the other has an empty slot, the other Pokémon will receive the Egg Move in the empty slot. In Gen 9, if a Pokémon holds a Mirror Herb, it will receive Egg Moves from the other regardless of species.
#define P_SCATTERBUG_LINE_FORM_BREED SPECIES_SCATTERBUG_FANCY // Choose the Scatterbug form all Vivillon/Spewpa/Scatterbug will breed into, basically aligning with the "location" of the player's game.
// Species-specific settings
#define P_SHEDINJA_BALL GEN_LATEST // Since Gen 4, Shedinja requires a Poké Ball for its evolution. In Gen 3, Shedinja inherits Nincada's Ball.

View File

@ -416,6 +416,7 @@
#define ANIM_TAG_BEAM (ANIM_SPRITES_START + 402)
#define ANIM_TAG_RED_EXPLOSION (ANIM_SPRITES_START + 403)
#define ANIM_TAG_PURPLE_CHAIN (ANIM_SPRITES_START + 404)
#define ANIM_TAG_PINKVIO_ORB (ANIM_SPRITES_START + 405)
// battlers
#define ANIM_ATTACKER 0

View File

@ -1,7 +1,7 @@
#ifndef GUARD_CONSTANTS_EXPANSION_H
#define GUARD_CONSTANTS_EXPANSION_H
// 1.10.0
// Last version: 1.9.3
#define EXPANSION_VERSION_MAJOR 1
#define EXPANSION_VERSION_MINOR 10
#define EXPANSION_VERSION_PATCH 0

View File

@ -86,4 +86,14 @@
#define DEOXYS_ROCK_SOLVED 2
#define DEOXYS_ROCK_COMPLETE 3
enum {
OPEN_PARTY_SCREEN,
NO_PARTY_SCREEN
};
enum {
CURRENT_POSITION,
TEMPLATE_POSITION
};
#endif // GUARD_CONSTANTS_FIELD_SPECIALS_H

View File

@ -1,171 +1,167 @@
#ifndef GUARD_HOLD_EFFECTS_H
#define GUARD_HOLD_EFFECTS_H
#define HOLD_EFFECT_NONE 0
#define HOLD_EFFECT_RESTORE_HP 1
#define HOLD_EFFECT_CURE_PAR 2
#define HOLD_EFFECT_CURE_SLP 3
#define HOLD_EFFECT_CURE_PSN 4
#define HOLD_EFFECT_CURE_BRN 5
#define HOLD_EFFECT_CURE_FRZ 6
#define HOLD_EFFECT_RESTORE_PP 7
#define HOLD_EFFECT_CURE_CONFUSION 8
#define HOLD_EFFECT_CURE_STATUS 9
#define HOLD_EFFECT_CONFUSE_SPICY 10
#define HOLD_EFFECT_CONFUSE_DRY 11
#define HOLD_EFFECT_CONFUSE_SWEET 12
#define HOLD_EFFECT_CONFUSE_BITTER 13
#define HOLD_EFFECT_CONFUSE_SOUR 14
#define HOLD_EFFECT_ATTACK_UP 15
#define HOLD_EFFECT_DEFENSE_UP 16
#define HOLD_EFFECT_SPEED_UP 17
#define HOLD_EFFECT_SP_ATTACK_UP 18
#define HOLD_EFFECT_SP_DEFENSE_UP 19
#define HOLD_EFFECT_CRITICAL_UP 20
#define HOLD_EFFECT_RANDOM_STAT_UP 21
#define HOLD_EFFECT_EVASION_UP 22
#define HOLD_EFFECT_RESTORE_STATS 23
#define HOLD_EFFECT_MACHO_BRACE 24
#define HOLD_EFFECT_EXP_SHARE 25
#define HOLD_EFFECT_QUICK_CLAW 26
#define HOLD_EFFECT_FRIENDSHIP_UP 27
#define HOLD_EFFECT_MENTAL_HERB 28
#define HOLD_EFFECT_CHOICE_BAND 29
#define HOLD_EFFECT_FLINCH 30
#define HOLD_EFFECT_BUG_POWER 31
#define HOLD_EFFECT_DOUBLE_PRIZE 32
#define HOLD_EFFECT_REPEL 33
#define HOLD_EFFECT_SOUL_DEW 34
#define HOLD_EFFECT_DEEP_SEA_TOOTH 35
#define HOLD_EFFECT_DEEP_SEA_SCALE 36
#define HOLD_EFFECT_CAN_ALWAYS_RUN 37
#define HOLD_EFFECT_PREVENT_EVOLVE 38
#define HOLD_EFFECT_FOCUS_BAND 39
#define HOLD_EFFECT_LUCKY_EGG 40
#define HOLD_EFFECT_SCOPE_LENS 41
#define HOLD_EFFECT_STEEL_POWER 42
#define HOLD_EFFECT_LEFTOVERS 43
#define HOLD_EFFECT_DRAGON_SCALE 44
#define HOLD_EFFECT_LIGHT_BALL 45
#define HOLD_EFFECT_GROUND_POWER 46
#define HOLD_EFFECT_ROCK_POWER 47
#define HOLD_EFFECT_GRASS_POWER 48
#define HOLD_EFFECT_DARK_POWER 49
#define HOLD_EFFECT_FIGHTING_POWER 50
#define HOLD_EFFECT_ELECTRIC_POWER 51
#define HOLD_EFFECT_WATER_POWER 52
#define HOLD_EFFECT_FLYING_POWER 53
#define HOLD_EFFECT_POISON_POWER 54
#define HOLD_EFFECT_ICE_POWER 55
#define HOLD_EFFECT_GHOST_POWER 56
#define HOLD_EFFECT_PSYCHIC_POWER 57
#define HOLD_EFFECT_FIRE_POWER 58
#define HOLD_EFFECT_DRAGON_POWER 59
#define HOLD_EFFECT_NORMAL_POWER 60
#define HOLD_EFFECT_UPGRADE 61
#define HOLD_EFFECT_SHELL_BELL 62
#define HOLD_EFFECT_LUCKY_PUNCH 63
#define HOLD_EFFECT_METAL_POWDER 64
#define HOLD_EFFECT_THICK_CLUB 65
#define HOLD_EFFECT_LEEK 66
enum ItemHoldEffect
{
HOLD_EFFECT_NONE,
HOLD_EFFECT_RESTORE_HP,
HOLD_EFFECT_CURE_PAR,
HOLD_EFFECT_CURE_SLP,
HOLD_EFFECT_CURE_PSN,
HOLD_EFFECT_CURE_BRN,
HOLD_EFFECT_CURE_FRZ,
HOLD_EFFECT_RESTORE_PP,
HOLD_EFFECT_CURE_CONFUSION,
HOLD_EFFECT_CURE_STATUS,
HOLD_EFFECT_CONFUSE_SPICY,
HOLD_EFFECT_CONFUSE_DRY,
HOLD_EFFECT_CONFUSE_SWEET,
HOLD_EFFECT_CONFUSE_BITTER,
HOLD_EFFECT_CONFUSE_SOUR,
HOLD_EFFECT_ATTACK_UP,
HOLD_EFFECT_DEFENSE_UP,
HOLD_EFFECT_SPEED_UP,
HOLD_EFFECT_SP_ATTACK_UP,
HOLD_EFFECT_SP_DEFENSE_UP,
HOLD_EFFECT_CRITICAL_UP,
HOLD_EFFECT_RANDOM_STAT_UP,
HOLD_EFFECT_EVASION_UP,
HOLD_EFFECT_RESTORE_STATS,
HOLD_EFFECT_MACHO_BRACE,
HOLD_EFFECT_EXP_SHARE,
HOLD_EFFECT_QUICK_CLAW,
HOLD_EFFECT_FRIENDSHIP_UP,
HOLD_EFFECT_MENTAL_HERB,
HOLD_EFFECT_CHOICE_BAND,
HOLD_EFFECT_FLINCH,
HOLD_EFFECT_BUG_POWER,
HOLD_EFFECT_DOUBLE_PRIZE,
HOLD_EFFECT_REPEL,
HOLD_EFFECT_SOUL_DEW,
HOLD_EFFECT_DEEP_SEA_TOOTH,
HOLD_EFFECT_DEEP_SEA_SCALE,
HOLD_EFFECT_CAN_ALWAYS_RUN,
HOLD_EFFECT_PREVENT_EVOLVE,
HOLD_EFFECT_FOCUS_BAND,
HOLD_EFFECT_LUCKY_EGG,
HOLD_EFFECT_SCOPE_LENS,
HOLD_EFFECT_STEEL_POWER,
HOLD_EFFECT_LEFTOVERS,
HOLD_EFFECT_DRAGON_SCALE,
HOLD_EFFECT_LIGHT_BALL,
HOLD_EFFECT_GROUND_POWER,
HOLD_EFFECT_ROCK_POWER,
HOLD_EFFECT_GRASS_POWER,
HOLD_EFFECT_DARK_POWER,
HOLD_EFFECT_FIGHTING_POWER,
HOLD_EFFECT_ELECTRIC_POWER,
HOLD_EFFECT_WATER_POWER,
HOLD_EFFECT_FLYING_POWER,
HOLD_EFFECT_POISON_POWER,
HOLD_EFFECT_ICE_POWER,
HOLD_EFFECT_GHOST_POWER,
HOLD_EFFECT_PSYCHIC_POWER,
HOLD_EFFECT_FIRE_POWER,
HOLD_EFFECT_DRAGON_POWER,
HOLD_EFFECT_NORMAL_POWER,
HOLD_EFFECT_UPGRADE,
HOLD_EFFECT_SHELL_BELL,
HOLD_EFFECT_LUCKY_PUNCH,
HOLD_EFFECT_METAL_POWDER,
HOLD_EFFECT_THICK_CLUB,
HOLD_EFFECT_LEEK,
// Gen4 hold effects.
HOLD_EFFECT_CHOICE_SCARF,
HOLD_EFFECT_CHOICE_SPECS,
HOLD_EFFECT_DAMP_ROCK,
HOLD_EFFECT_GRIP_CLAW,
HOLD_EFFECT_HEAT_ROCK,
HOLD_EFFECT_ICY_ROCK,
HOLD_EFFECT_LIGHT_CLAY,
HOLD_EFFECT_SMOOTH_ROCK,
HOLD_EFFECT_POWER_HERB,
HOLD_EFFECT_BIG_ROOT,
HOLD_EFFECT_EXPERT_BELT,
HOLD_EFFECT_LIFE_ORB,
HOLD_EFFECT_METRONOME,
HOLD_EFFECT_MUSCLE_BAND,
HOLD_EFFECT_WIDE_LENS,
HOLD_EFFECT_WISE_GLASSES,
HOLD_EFFECT_ZOOM_LENS,
HOLD_EFFECT_LAGGING_TAIL,
HOLD_EFFECT_FOCUS_SASH,
HOLD_EFFECT_FLAME_ORB,
HOLD_EFFECT_TOXIC_ORB,
HOLD_EFFECT_STICKY_BARB,
HOLD_EFFECT_IRON_BALL,
HOLD_EFFECT_BLACK_SLUDGE,
HOLD_EFFECT_DESTINY_KNOT,
HOLD_EFFECT_SHED_SHELL,
HOLD_EFFECT_QUICK_POWDER,
HOLD_EFFECT_ADAMANT_ORB,
HOLD_EFFECT_LUSTROUS_ORB,
HOLD_EFFECT_GRISEOUS_ORB,
HOLD_EFFECT_ENIGMA_BERRY,
HOLD_EFFECT_RESIST_BERRY,
HOLD_EFFECT_POWER_ITEM,
HOLD_EFFECT_RESTORE_PCT_HP,
HOLD_EFFECT_MICLE_BERRY,
HOLD_EFFECT_CUSTAP_BERRY,
HOLD_EFFECT_JABOCA_BERRY,
HOLD_EFFECT_ROWAP_BERRY,
HOLD_EFFECT_KEE_BERRY,
HOLD_EFFECT_MARANGA_BERRY,
HOLD_EFFECT_PLATE,
// Gen5 hold effects
HOLD_EFFECT_FLOAT_STONE,
HOLD_EFFECT_EVIOLITE,
HOLD_EFFECT_ASSAULT_VEST,
HOLD_EFFECT_DRIVE,
HOLD_EFFECT_GEMS,
HOLD_EFFECT_ROCKY_HELMET,
HOLD_EFFECT_AIR_BALLOON,
HOLD_EFFECT_RED_CARD,
HOLD_EFFECT_RING_TARGET,
HOLD_EFFECT_BINDING_BAND,
HOLD_EFFECT_EJECT_BUTTON,
HOLD_EFFECT_ABSORB_BULB,
HOLD_EFFECT_CELL_BATTERY,
// Gen6 hold effects
HOLD_EFFECT_FAIRY_POWER,
HOLD_EFFECT_MEGA_STONE,
HOLD_EFFECT_SAFETY_GOGGLES,
HOLD_EFFECT_LUMINOUS_MOSS,
HOLD_EFFECT_SNOWBALL,
HOLD_EFFECT_WEAKNESS_POLICY,
HOLD_EFFECT_PRIMAL_ORB,
// Gen7 hold effects
HOLD_EFFECT_PROTECTIVE_PADS,
HOLD_EFFECT_TERRAIN_EXTENDER,
HOLD_EFFECT_SEEDS,
HOLD_EFFECT_ADRENALINE_ORB,
HOLD_EFFECT_MEMORY,
HOLD_EFFECT_Z_CRYSTAL,
// Gen8 hold effects
HOLD_EFFECT_UTILITY_UMBRELLA,
HOLD_EFFECT_EJECT_PACK,
HOLD_EFFECT_ROOM_SERVICE,
HOLD_EFFECT_BLUNDER_POLICY,
HOLD_EFFECT_HEAVY_DUTY_BOOTS,
HOLD_EFFECT_THROAT_SPRAY,
// Gen9 hold effects
HOLD_EFFECT_ABILITY_SHIELD,
HOLD_EFFECT_CLEAR_AMULET,
HOLD_EFFECT_MIRROR_HERB,
HOLD_EFFECT_PUNCHING_GLOVE,
HOLD_EFFECT_COVERT_CLOAK,
HOLD_EFFECT_LOADED_DICE,
HOLD_EFFECT_BOOSTER_ENERGY,
HOLD_EFFECT_OGERPON_MASK,
// Gen2 hold effect
HOLD_EFFECT_BERSERK_GENE,
};
// Gen4 hold effects.
#define HOLD_EFFECT_CHOICE_SCARF 67
#define HOLD_EFFECT_CHOICE_SPECS 68
#define HOLD_EFFECT_DAMP_ROCK 69
#define HOLD_EFFECT_GRIP_CLAW 70
#define HOLD_EFFECT_HEAT_ROCK 71
#define HOLD_EFFECT_ICY_ROCK 72
#define HOLD_EFFECT_LIGHT_CLAY 73
#define HOLD_EFFECT_SMOOTH_ROCK 74
#define HOLD_EFFECT_POWER_HERB 75
#define HOLD_EFFECT_BIG_ROOT 76
#define HOLD_EFFECT_EXPERT_BELT 77
#define HOLD_EFFECT_LIFE_ORB 78
#define HOLD_EFFECT_METRONOME 79
#define HOLD_EFFECT_MUSCLE_BAND 80
#define HOLD_EFFECT_WIDE_LENS 81
#define HOLD_EFFECT_WISE_GLASSES 82
#define HOLD_EFFECT_ZOOM_LENS 83
#define HOLD_EFFECT_LAGGING_TAIL 84
#define HOLD_EFFECT_FOCUS_SASH 85
#define HOLD_EFFECT_FLAME_ORB 86
#define HOLD_EFFECT_TOXIC_ORB 87
#define HOLD_EFFECT_STICKY_BARB 88
#define HOLD_EFFECT_IRON_BALL 89
#define HOLD_EFFECT_BLACK_SLUDGE 90
#define HOLD_EFFECT_DESTINY_KNOT 91
#define HOLD_EFFECT_SHED_SHELL 92
#define HOLD_EFFECT_QUICK_POWDER 93
#define HOLD_EFFECT_ADAMANT_ORB 94
#define HOLD_EFFECT_LUSTROUS_ORB 95
#define HOLD_EFFECT_GRISEOUS_ORB 96
#define HOLD_EFFECT_ENIGMA_BERRY 97
#define HOLD_EFFECT_RESIST_BERRY 98
#define HOLD_EFFECT_POWER_ITEM 99
#define HOLD_EFFECT_RESTORE_PCT_HP 100
#define HOLD_EFFECT_MICLE_BERRY 101
#define HOLD_EFFECT_CUSTAP_BERRY 102
#define HOLD_EFFECT_JABOCA_BERRY 103
#define HOLD_EFFECT_ROWAP_BERRY 104
#define HOLD_EFFECT_KEE_BERRY 105
#define HOLD_EFFECT_MARANGA_BERRY 106
#define HOLD_EFFECT_PLATE 107
// Gen5 hold effects
#define HOLD_EFFECT_FLOAT_STONE 117
#define HOLD_EFFECT_EVIOLITE 118
#define HOLD_EFFECT_ASSAULT_VEST 119
#define HOLD_EFFECT_DRIVE 120
#define HOLD_EFFECT_GEMS 121
#define HOLD_EFFECT_ROCKY_HELMET 122
#define HOLD_EFFECT_AIR_BALLOON 123
#define HOLD_EFFECT_RED_CARD 124
#define HOLD_EFFECT_RING_TARGET 125
#define HOLD_EFFECT_BINDING_BAND 126
#define HOLD_EFFECT_EJECT_BUTTON 127
#define HOLD_EFFECT_ABSORB_BULB 128
#define HOLD_EFFECT_CELL_BATTERY 129
// Gen6 hold effects
#define HOLD_EFFECT_FAIRY_POWER 139
#define HOLD_EFFECT_MEGA_STONE 140
#define HOLD_EFFECT_SAFETY_GOGGLES 141
#define HOLD_EFFECT_LUMINOUS_MOSS 142
#define HOLD_EFFECT_SNOWBALL 143
#define HOLD_EFFECT_WEAKNESS_POLICY 144
#define HOLD_EFFECT_PRIMAL_ORB 145
// Gen7 hold effects
#define HOLD_EFFECT_PROTECTIVE_PADS 154
#define HOLD_EFFECT_TERRAIN_EXTENDER 155
#define HOLD_EFFECT_SEEDS 156
#define HOLD_EFFECT_ADRENALINE_ORB 157
#define HOLD_EFFECT_MEMORY 158
#define HOLD_EFFECT_Z_CRYSTAL 159
// Gen8 hold effects
#define HOLD_EFFECT_UTILITY_UMBRELLA 169
#define HOLD_EFFECT_EJECT_PACK 170
#define HOLD_EFFECT_ROOM_SERVICE 171
#define HOLD_EFFECT_BLUNDER_POLICY 172
#define HOLD_EFFECT_HEAVY_DUTY_BOOTS 173
#define HOLD_EFFECT_THROAT_SPRAY 174
// Gen9 hold effects
#define HOLD_EFFECT_ABILITY_SHIELD 175
#define HOLD_EFFECT_CLEAR_AMULET 176
#define HOLD_EFFECT_MIRROR_HERB 177
#define HOLD_EFFECT_PUNCHING_GLOVE 178
#define HOLD_EFFECT_COVERT_CLOAK 179
#define HOLD_EFFECT_LOADED_DICE 180
#define HOLD_EFFECT_BOOSTER_ENERGY 181
#define HOLD_EFFECT_OGERPON_MASK 182
// Gen2 hold effect
#define HOLD_EFFECT_BERSERK_GENE 184
#define HOLD_EFFECT_CHOICE(holdEffect)((holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF || holdEffect == HOLD_EFFECT_CHOICE_SPECS))
#define HOLD_EFFECT_CHOICE(holdEffect) ((holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF || holdEffect == HOLD_EFFECT_CHOICE_SPECS))
// Terrain seed params
#define HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN 0

View File

@ -1327,4 +1327,18 @@ enum {
#define DEX_HGSS_Y_BOTTOM_PADDING 4
#define DEX_HGSS_MEASUREMENT_X_PADDING 51
enum
{
DEX_MODE_HOENN,
DEX_MODE_NATIONAL
};
enum
{
FLAG_GET_SEEN,
FLAG_GET_CAUGHT,
FLAG_SET_SEEN,
FLAG_SET_CAUGHT
};
#endif // GUARD_CONSTANTS_POKEDEX_H

View File

@ -127,6 +127,7 @@ bool8 TryGetObjectEventIdByLocalIdAndMap(u8 localId, u8 mapNum, u8 mapGroupId, u
u8 GetObjectEventIdByXY(s16 x, s16 y);
void SetObjectEventDirection(struct ObjectEvent *objectEvent, u8 direction);
u8 GetFirstInactiveObjectEventId(void);
u8 GetObjectEventIdByLocalId(u8);
void RemoveObjectEventByLocalIdAndMap(u8 localId, u8 mapNum, u8 mapGroup);
void LoadSpecialObjectReflectionPalette(u16 tag, u8 slot);
void TryMoveObjectEventToMapCoords(u8 localId, u8 mapNum, u8 mapGroup, s16 x, s16 y);
@ -211,6 +212,7 @@ void ObjectEventForceSetHeldMovement(struct ObjectEvent *objectEvent, u8 movemen
bool8 ObjectEventIsMovementOverridden(struct ObjectEvent *objectEvent);
u8 ObjectEventCheckHeldMovementStatus(struct ObjectEvent *objectEvent);
u8 ObjectEventGetHeldMovementActionId(struct ObjectEvent *objectEvent);
const struct ObjectEventTemplate *FindObjectEventTemplateByLocalId(u8, const struct ObjectEventTemplate *, u8);
void TryOverrideTemplateCoordsForObjectEvent(const struct ObjectEvent *objectEvent, u8 movementType);
void OverrideTemplateCoordsForObjectEvent(const struct ObjectEvent *objectEvent);
void ShiftStillObjectEventCoords(struct ObjectEvent *objEvent);

View File

@ -404,6 +404,7 @@ extern const u8 EventScript_FailSweetScent[];
extern const u8 EventScript_UseFlash[];
extern const u8 EventScript_UseCut[];
extern const u8 EventScript_UseRockSmash[];
extern const u8 EventScript_UseDig[];
//player pc
extern const u8 LittlerootTown_BrendansHouse_2F_EventScript_TurnOffPlayerPC[];

View File

@ -33,5 +33,8 @@ void ResetFanClub(void);
bool8 ShouldShowBoxWasFullMessage(void);
void SetPCBoxToSendMon(u8 boxId);
void PreparePartyForSkyBattle(void);
void GetObjectPosition(u16*, u16*, u32, u32);
bool32 CheckObjectAtXY(u32, u32);
bool32 CheckPartyHasSpecies(u32);
#endif // GUARD_FIELD_SPECIALS_H

View File

@ -2887,6 +2887,8 @@ extern const u32 gBattleAnimSpritePal_IvyCudgelGrass[];
extern const u32 gBattleAnimSpritePal_IvyCudgelFire[];
extern const u32 gBattleAnimSpritePal_IvyCudgelRock[];
extern const u32 gBattleAnimSpritePal_IvyCudgelWater[];
extern const u32 gBattleAnimSpriteGfx_PinkVioletOrb[];
extern const u32 gBattleAnimSpritePal_PinkVioletOrb[];
extern const u32 gBattleAnimBgImage_Dark[];
extern const u32 gBattleAnimBgImage_Ghost[];

View File

@ -344,5 +344,6 @@ bool8 DoesLinkPlayerCountMatchSaved(void);
void SetCloseLinkCallbackAndType(u16 type);
bool32 IsSendingKeysToLink(void);
u32 GetLinkRecvQueueLength(void);
bool32 ShouldCheckForUnionRoom(void);
#endif // GUARD_LINK_H

View File

@ -4,20 +4,6 @@
extern u8 gUnusedPokedexU8;
extern void (*gPokedexVBlankCB)(void);
enum
{
DEX_MODE_HOENN,
DEX_MODE_NATIONAL
};
enum
{
FLAG_GET_SEEN,
FLAG_GET_CAUGHT,
FLAG_SET_SEEN,
FLAG_SET_CAUGHT
};
void ResetPokedex(void);
u16 GetNationalPokedexCount(u8);
u16 GetHoennPokedexCount(u8);

View File

@ -163,7 +163,12 @@ enum RandomTag
RNG_AI_ABILITY,
RNG_AI_SWITCH_HASBADODDS,
RNG_AI_SWITCH_WONDER_GUARD,
RNG_AI_SWITCH_BADLY_POISONED,
RNG_AI_SWITCH_CURSED,
RNG_AI_SWITCH_NIGHTMARE,
RNG_AI_SWITCH_SEEDED,
RNG_SHELL_SIDE_ARM,
RNG_RANDOM_TARGET,
RNG_DEXNAV_ENCOUNTER_LEVEL,
};

View File

@ -645,6 +645,15 @@ struct AILogLine
s16 score;
};
// Data which is updated by the test runner during a battle and needs to
// be reset between trials.
struct BattleTrialData
{
u8 lastActionTurn;
u8 queuedEvent;
u8 aiActionsPlayed[MAX_BATTLERS_COUNT];
};
struct BattleTestData
{
u8 stack[BATTLE_TEST_STACK_SIZE];
@ -676,20 +685,19 @@ struct BattleTestData
u8 battleRecordSourceLineOffsets[MAX_BATTLERS_COUNT][BATTLER_RECORD_SIZE];
u16 recordIndexes[MAX_BATTLERS_COUNT];
struct BattlerTurn battleRecordTurns[MAX_TURNS][MAX_BATTLERS_COUNT];
u8 lastActionTurn;
u8 queuedEventsCount;
u8 queueGroupType;
u8 queueGroupStart;
u8 queuedEvent;
struct QueuedEvent queuedEvents[MAX_QUEUED_EVENTS];
u8 expectedAiActionIndex[MAX_BATTLERS_COUNT];
u8 aiActionsPlayed[MAX_BATTLERS_COUNT];
struct ExpectedAIAction expectedAiActions[MAX_BATTLERS_COUNT][MAX_EXPECTED_ACTIONS];
struct ExpectedAiScore expectedAiScores[MAX_BATTLERS_COUNT][MAX_TURNS][MAX_AI_SCORE_COMPARISION_PER_TURN]; // Max 4 comparisions per turn
struct AILogLine aiLogLines[MAX_BATTLERS_COUNT][MAX_MON_MOVES][MAX_AI_LOG_LINES];
u8 aiLogPrintedForMove[MAX_BATTLERS_COUNT]; // Marks ai score log as printed for move, so the same log isn't displayed multiple times.
u16 flagId;
struct BattleTrialData trial;
};
struct BattleTestRunnerState

View File

@ -19,6 +19,7 @@ SECTIONS {
{
__ewram_start = .;
*(.ewram*)
. = ALIGN(4);
__ewram_end = .;
} > EWRAM
@ -34,6 +35,7 @@ SECTIONS {
{
__iwram_start = .;
*(.iwram*);
. = ALIGN(4);
__iwram_end = .;
} > IWRAM

View File

@ -27,6 +27,7 @@ SECTIONS {
src/*.o(.sbss);
gflib/*.o(.sbss);
test/*.o(.sbss);
. = ALIGN(4);
} > EWRAM
.iwram ORIGIN(IWRAM) : AT (__iwram_lma)
@ -34,6 +35,7 @@ SECTIONS {
{
__iwram_start = .;
*(.iwram*);
. = ALIGN(4);
__iwram_end = .;
} > IWRAM
@ -55,6 +57,7 @@ SECTIONS {
data/*.o(COMMON);
test/*.o(COMMON);
*libc.a:sbrkr.o(COMMON);
. = ALIGN(4);
/* .persistent starts at 0x3007F00 */
/* WARNING: This is the end of the IRQ stack, if there's too

View File

@ -477,6 +477,7 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData)
// get/assume all battler data and simulate AI damage
battlersCount = gBattlersCount;
AI_DATA->aiCalcInProgress = TRUE;
for (battlerAtk = 0; battlerAtk < battlersCount; battlerAtk++)
{
if (!IsBattlerAlive(battlerAtk))
@ -492,6 +493,7 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData)
SetBattlerAiMovesData(aiData, battlerAtk, battlersCount);
}
AI_DATA->aiCalcInProgress = FALSE;
}
static bool32 AI_SwitchMonIfSuitable(u32 battler, bool32 doubleBattle)
@ -873,6 +875,12 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// target ability checks
if (!DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
{
if (CanAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[battlerDef]))
RETURN_SCORE_MINUS(20);
if (CanAbilityAbsorbMove(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, moveType))
RETURN_SCORE_MINUS(20);
switch (aiData->abilities[battlerDef])
{
case ABILITY_MAGIC_GUARD:
@ -903,12 +911,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
&& (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG))
RETURN_SCORE_MINUS(10);
break;
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (atkPriority > 0)
RETURN_SCORE_MINUS(10);
break;
case ABILITY_AROMA_VEIL:
if (IsAromaVeilProtectedMove(move))
RETURN_SCORE_MINUS(10);
@ -972,37 +974,14 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
&& IsNonVolatileStatusMoveEffect(moveEffect))
RETURN_SCORE_MINUS(10);
break;
case ABILITY_LIGHTNING_ROD:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_MOTOR_DRIVE:
case ABILITY_VOLT_ABSORB:
if (moveType == TYPE_ELECTRIC)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_WATER_ABSORB:
case ABILITY_DRY_SKIN:
if (moveType == TYPE_WATER)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_EARTH_EATER:
if (moveType == TYPE_GROUND)
RETURN_SCORE_MINUS(20);
break;
} // def ability checks
// target partner ability checks & not attacking partner
if (isDoubleBattle)
{
if (CanPartnerAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[BATTLE_PARTNER(battlerDef)]))
RETURN_SCORE_MINUS(20);
switch (aiData->abilities[BATTLE_PARTNER(battlerDef)])
{
case ABILITY_LIGHTNING_ROD:
@ -1029,12 +1008,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (IsAromaVeilProtectedMove(move))
RETURN_SCORE_MINUS(10);
break;
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (atkPriority > 0)
RETURN_SCORE_MINUS(10);
break;
}
} // def partner ability checks
} // ignore def ability check
@ -1046,19 +1019,19 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
RETURN_SCORE_MINUS(10);
// terrain & effect checks
if (AI_IsTerrainAffected(battlerDef, STATUS_FIELD_ELECTRIC_TERRAIN))
if (IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_ELECTRIC_TERRAIN))
{
if (moveEffect == EFFECT_SLEEP || moveEffect == EFFECT_YAWN)
RETURN_SCORE_MINUS(20);
}
if (AI_IsTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN))
if (IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN))
{
if (IsNonVolatileStatusMoveEffect(moveEffect) || IsConfusionMoveEffect(moveEffect))
RETURN_SCORE_MINUS(20);
}
if (AI_IsTerrainAffected(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN) && atkPriority > 0)
if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN) && atkPriority > 0)
{
RETURN_SCORE_MINUS(20);
}
@ -1279,10 +1252,10 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (isDoubleBattle)
{
if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS)
&& AI_IsBattlerGrounded(battlerAtk)
&& IsBattlerGrounded(battlerAtk)
&& (BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK)))
&& !(IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), TYPE_GRASS)
&& AI_IsBattlerGrounded(BATTLE_PARTNER(battlerAtk))
&& IsBattlerGrounded(BATTLE_PARTNER(battlerAtk))
&& aiData->abilities[BATTLE_PARTNER(battlerAtk)] != ABILITY_CONTRARY
&& (BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_ATK)
|| BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPATK))))
@ -1291,7 +1264,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
}
}
else if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS)
&& AI_IsBattlerGrounded(battlerAtk)
&& IsBattlerGrounded(battlerAtk)
&& (BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK))))
{
ADJUST_SCORE(-10);
@ -3348,6 +3321,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
case EFFECT_ABSORB:
if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_BIG_ROOT && effectiveness >= AI_EFFECTIVENESS_x1)
ADJUST_SCORE(DECENT_EFFECT);
break;
case EFFECT_EXPLOSION:
case EFFECT_MEMENTO:
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7)
@ -3362,7 +3336,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
break;
case EFFECT_MIRROR_MOVE:
if (predictedMove != MOVE_NONE)
return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score);
return AI_CheckViability(battlerAtk, battlerDef, predictedMove, score);
break;
case EFFECT_ATTACK_UP:
case EFFECT_ATTACK_UP_USER_ALLY:
@ -3662,12 +3636,12 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
{
switch (ShouldPivot(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, movesetIndex))
{
case 0: // no
case DONT_PIVOT:
ADJUST_SCORE(-10); // technically should go in CheckBadMove, but this is easier/less computationally demanding
break;
case 1: // maybe
case CAN_TRY_PIVOT:
break;
case 2: // yes
case SHOULD_PIVOT:
ADJUST_SCORE(BEST_EFFECT);
break;
}
@ -3975,7 +3949,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(DECENT_EFFECT);
break;
case EFFECT_SAFEGUARD:
if (!AI_IsTerrainAffected(battlerAtk, STATUS_FIELD_MISTY_TERRAIN) || !IsBattlerGrounded(battlerAtk))
if (!IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_MISTY_TERRAIN) || !IsBattlerGrounded(battlerAtk))
ADJUST_SCORE(DECENT_EFFECT); // TODO: check if opp has status move?
//if (CountUsablePartyMons(battlerDef) != 0)
//ADJUST_SCORE(8);

View File

@ -180,7 +180,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4)))
{
// 50% chance to stay in regardless
if (!RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50))
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50))
return FALSE;
// Switch mon out
@ -203,7 +203,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
return FALSE;
// 50% chance to stay in regardless
if (!RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50))
if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50))
return FALSE;
// Switch mon out
@ -462,16 +462,12 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
u16 holdEffect = AI_DATA->holdEffects[battler];
u8 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler));
u8 opposingBattler = GetBattlerAtPosition(opposingPosition);
s32 moduloChance = 4; //25% Chance Default
s32 chanceReducer = 1; //No Reduce default. Increase to reduce
bool32 hasStatRaised = AnyStatIsRaised(battler);
s32 firstId;
s32 lastId;
s32 i;
struct Pokemon *party;
if (AnyStatIsRaised(battler))
chanceReducer = 5; // Reduce switchout probability by factor of 5 if setup
//Perish Song
if (gStatuses3[battler] & STATUS3_PERISH_SONG
&& gDisableStructs[battler].perishSongTimer == 0
@ -567,28 +563,24 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
&& !AiExpectsToFaintPlayer(battler))
{
//Toxic
moduloChance = 2; //50%
if (((gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >= STATUS1_TOXIC_TURN(2))
&& gBattleMons[battler].hp >= (gBattleMons[battler].maxHP / 3)
&& (Random() % (moduloChance*chanceReducer)) == 0)
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, 20) : RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, 50)))
switchMon = TRUE;
//Cursed
moduloChance = 2; //50%
if (gBattleMons[battler].status2 & STATUS2_CURSED
&& (Random() % (moduloChance*chanceReducer)) == 0)
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_CURSED, 20) : RandomPercentage(RNG_AI_SWITCH_CURSED, 50)))
switchMon = TRUE;
//Nightmare
moduloChance = 3; //33.3%
if (gBattleMons[battler].status2 & STATUS2_NIGHTMARE
&& (Random() % (moduloChance*chanceReducer)) == 0)
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, 15) : RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, 33)))
switchMon = TRUE;
//Leech Seed
moduloChance = 4; //25%
if (gStatuses3[battler] & STATUS3_LEECHSEED
&& (Random() % (moduloChance*chanceReducer)) == 0)
&& (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_SEEDED, 10) : RandomPercentage(RNG_AI_SWITCH_SEEDED, 25)))
switchMon = TRUE;
}
@ -606,7 +598,7 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
if (FindMonThatAbsorbsOpponentsMove(battler, FALSE)) // Switch if absorber found. Note: FindMonThatAbsorbsOpponentsMove already provides id of the mon to switch into to gBattleStruct->AI_monToSwitchIntoId.
switchMon = TRUE, monIdChosen = TRUE;
if (!AI_OpponentCanFaintAiWithMod(battler, 0)
&& AnyStatIsRaised(battler))
&& hasStatRaised)
switchMon = FALSE;
if (AiExpectsToFaintPlayer(battler)
&& AI_IsSlower(battler, opposingBattler, 0)

View File

@ -402,12 +402,19 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef)
{
struct AiLogicData *aiData = AI_DATA;
u32 battlerDefAbility;
u32 partnerBattlerDefAbility;
u32 moveType = GetMoveType(move);
if (DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
{
battlerDefAbility = ABILITY_NONE;
partnerBattlerDefAbility = ABILITY_NONE;
}
else
{
battlerDefAbility = aiData->abilities[battlerDef];
partnerBattlerDefAbility = aiData->abilities[BATTLE_PARTNER(battlerDef)];
}
if (battlerDef == BATTLE_PARTNER(battlerAtk))
battlerDefAbility = aiData->abilities[battlerDef];
@ -415,47 +422,14 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef)
if (gBattleStruct->commandingDondozo & (1u << battlerDef))
return TRUE;
switch (battlerDefAbility)
{
case ABILITY_LIGHTNING_ROD:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_VOLT_ABSORB:
case ABILITY_MOTOR_DRIVE:
if (moveType == TYPE_ELECTRIC)
return TRUE;
break;
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY < GEN_5)
break;
// Fallthrough
case ABILITY_WATER_ABSORB:
case ABILITY_DRY_SKIN:
if (moveType == TYPE_WATER)
return TRUE;
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE)
return TRUE;
break;
case ABILITY_SOUNDPROOF:
if (gMovesInfo[move].soundMove)
return TRUE;
break;
case ABILITY_BULLETPROOF:
if (gMovesInfo[move].ballisticMove)
return TRUE;
break;
case ABILITY_SAP_SIPPER:
if (moveType == TYPE_GRASS)
return TRUE;
break;
case ABILITY_EARTH_EATER:
if (moveType == TYPE_GROUND)
return TRUE;
break;
}
if (CanAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[battlerDef]))
return TRUE;
if (CanPartnerAbilityBlockMove(battlerAtk, battlerDef, move, partnerBattlerDefAbility))
return TRUE;
if (CanAbilityAbsorbMove(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, moveType))
return TRUE;
switch (gMovesInfo[move].effect)
{
@ -526,7 +500,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
bool32 isDamageMoveUnusable = FALSE;
bool32 toggledGimmick = FALSE;
struct AiLogicData *aiData = AI_DATA;
gBattleStruct->aiCalcInProgress = TRUE;
AI_DATA->aiCalcInProgress = TRUE;
if (moveEffect == EFFECT_NATURE_POWER)
move = GetNaturePowerMove(battlerAtk);
@ -736,12 +710,11 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
*typeEffectiveness = AI_GetEffectiveness(effectivenessMultiplier);
// Undo temporary settings
gBattleStruct->aiCalcInProgress = FALSE;
gBattleStruct->swapDamageCategory = FALSE;
gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE;
if (toggledGimmick)
SetActiveGimmick(battlerAtk, GIMMICK_NONE);
AI_DATA->aiCalcInProgress = FALSE;
return simDamage;
}
@ -1371,42 +1344,6 @@ u32 AI_DecideHoldEffectForTurn(u32 battlerId)
return holdEffect;
}
bool32 AI_IsTerrainAffected(u32 battlerId, u32 flags)
{
if (gStatuses3[battlerId] & STATUS3_SEMI_INVULNERABLE)
return FALSE;
else if (!(gFieldStatuses & flags))
return FALSE;
return AI_IsBattlerGrounded(battlerId);
}
// different from IsBattlerGrounded in that we don't always know battler's hold effect or ability
bool32 AI_IsBattlerGrounded(u32 battlerId)
{
u32 holdEffect = AI_DATA->holdEffects[battlerId];
if (holdEffect == HOLD_EFFECT_IRON_BALL)
return TRUE;
else if (gFieldStatuses & STATUS_FIELD_GRAVITY)
return TRUE;
else if (gStatuses3[battlerId] & STATUS3_ROOTED)
return TRUE;
else if (gStatuses3[battlerId] & STATUS3_SMACKED_DOWN)
return TRUE;
else if (gStatuses3[battlerId] & STATUS3_TELEKINESIS)
return FALSE;
else if (gStatuses3[battlerId] & STATUS3_MAGNET_RISE)
return FALSE;
else if (holdEffect == HOLD_EFFECT_AIR_BALLOON)
return FALSE;
else if (AI_DATA->abilities[battlerId] == ABILITY_LEVITATE)
return FALSE;
else if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING))
return FALSE;
else
return TRUE;
}
bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move)
{
if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE)
@ -2712,12 +2649,7 @@ static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler)
return FALSE;
}
enum {
DONT_PIVOT,
CAN_TRY_PIVOT,
PIVOT,
};
bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex)
enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex)
{
bool32 hasStatBoost = AnyUsefulStatIsRaised(battlerAtk) || gBattleMons[battlerDef].statStages[STAT_EVASION] >= 9; //Significant boost in evasion for any class
u32 battlerToSwitch;
@ -2734,7 +2666,7 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
//TODO - predict opponent switching
/*if (IsPredictedToSwitch(battlerDef, battlerAtk) && !hasStatBoost)
return PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/
return SHOULD_PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/
if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker goes first
{
@ -2744,14 +2676,14 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
{
// attacker can kill target in two hits (theoretically)
if (CanTargetFaintAi(battlerDef, battlerAtk))
return PIVOT; // Won't get the two turns, pivot
return SHOULD_PIVOT; // Won't get the two turns, pivot
if (!IS_MOVE_STATUS(move) && ((AI_DATA->shouldSwitch & (1u << battlerAtk))
|| (AtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|| (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY)
|| defAbility == ABILITY_MULTISCALE
|| defAbility == ABILITY_SHADOW_SHIELD))))
return PIVOT; // pivot to break sash/sturdy/multiscale
return SHOULD_PIVOT; // pivot to break sash/sturdy/multiscale
}
else if (!hasStatBoost)
{
@ -2759,17 +2691,17 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
|| (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY)
|| defAbility == ABILITY_MULTISCALE
|| defAbility == ABILITY_SHADOW_SHIELD)))
return PIVOT; // pivot to break sash/sturdy/multiscale
return SHOULD_PIVOT; // pivot to break sash/sturdy/multiscale
if (AI_DATA->shouldSwitch & (1u << battlerAtk))
return PIVOT;
return SHOULD_PIVOT;
/* TODO - check if switchable mon unafffected by/will remove hazards
if (gSideStatuses[battlerAtk] & SIDE_STATUS_SPIKES && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS)
return PIVOT;*/
return SHOULD_PIVOT;*/
/*if (BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]) && switchScore >= SWITCHING_INCREASE_WALLS_FOE)
return PIVOT;*/
return SHOULD_PIVOT;*/
/*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE)
{
@ -2780,20 +2712,20 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
if (physMoveInMoveset && !specMoveInMoveset)
{
if (STAT_STAGE_ATK < 6)
return PIVOT;
return SHOULD_PIVOT;
}
else if (!physMoveInMoveset && specMoveInMoveset)
{
if (STAT_STAGE_SPATK < 6)
return PIVOT;
return SHOULD_PIVOT;
}
else if (physMoveInMoveset && specMoveInMoveset)
{
if (STAT_STAGE_ATK < 6 && STAT_STAGE_SPATK < 6)
return PIVOT;
return SHOULD_PIVOT;
}
return CAN_TRY_PIVOT;
return SHOULD_PIVOT;
}*/
}
}
@ -2816,7 +2748,7 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
}
else // Can't KO the foe
{
return PIVOT;
return SHOULD_PIVOT;
}
}
else // Foe can 3HKO+ AI
@ -2842,17 +2774,17 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
else
{
//if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_KO_FOE)
//return PIVOT; //Only switch if way better matchup
//return SHOULD_PIVOT; //Only switch if way better matchup
if (!hasStatBoost)
{
// TODO - check if switching prevents/removes hazards
//if (gSideStatuses[battlerAtk] & SIDE_STATUS_SPIKES && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS)
//return PIVOT;
//return SHOULD_PIVOT;
// TODO - not always a good idea
//if (BattlerWillFaintFromSecondaryDamage(battlerAtk) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE)
//return PIVOT;
//return SHOULD_PIVOT;
/*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE)
{
@ -2863,17 +2795,17 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
if (physMoveInMoveset && !specMoveInMoveset)
{
if (STAT_STAGE_ATK < 6)
return PIVOT;
return SHOULD_PIVOT;
}
else if (!physMoveInMoveset && specMoveInMoveset)
{
if (STAT_STAGE_SPATK < 6)
return PIVOT;
return SHOULD_PIVOT;
}
else if (physMoveInMoveset && specMoveInMoveset)
{
if (STAT_STAGE_ATK < 6 && STAT_STAGE_SPATK < 6)
return PIVOT;
return SHOULD_PIVOT;
}
}*/

View File

@ -953,6 +953,18 @@ const struct SpriteTemplate gRedHeartRisingSpriteTemplate =
.callback = AnimRedHeartRising,
};
// New struct that's just a copy of 'gMagentaHeartSpriteTemplate', without need to make new anim tags
const struct SpriteTemplate gRedHeartCharmSpriteTemplate =
{
.tileTag = ANIM_TAG_RED_HEART,
.paletteTag = ANIM_TAG_RED_HEART,
.oam = &gOamData_AffineOff_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimMagentaHeart,
};
const union AffineAnimCmd gHiddenPowerOrbAffineAnimCmds[] =
{
AFFINEANIMCMD_FRAME(0x80, 0x80, 0, 0),

View File

@ -29,6 +29,8 @@ static bool8 CreateShockWaveBoltSprite(struct Task *task, u8 taskId);
static void AnimShockWaveProgressingBolt(struct Sprite *);
static bool8 CreateShockWaveLightningSprite(struct Task *task, u8 taskId);
static void AnimShockWaveLightning(struct Sprite *sprite);
static void AnimIon(struct Sprite *);
static void AnimIon_Step(struct Sprite *);
static const union AnimCmd sAnim_Lightning[] =
{
@ -559,6 +561,34 @@ const struct SpriteTemplate gSeedFlareGreenChargeTemplate =
.callback = AnimGrowingChargeOrb
};
static const union AnimCmd sAnim_Ion[] =
{
ANIMCMD_FRAME(0, 2),
ANIMCMD_FRAME(8, 2),
ANIMCMD_FRAME(16, 2),
ANIMCMD_FRAME(24, 6),
ANIMCMD_FRAME(32, 2),
ANIMCMD_FRAME(40, 2),
ANIMCMD_FRAME(48, 2),
ANIMCMD_END,
};
static const union AnimCmd *const sAnims_Ion[] =
{
sAnim_Ion,
};
const struct SpriteTemplate gIonSpriteTemplate =
{
.tileTag = ANIM_TAG_IONS,
.paletteTag = ANIM_TAG_IONS,
.oam = &gOamData_AffineOff_ObjNormal_16x32,
.anims = sAnims_Ion,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimIon,
};
// functions
static void AnimLightning(struct Sprite *sprite)
{
@ -1452,3 +1482,44 @@ static void AnimShockWaveLightning(struct Sprite *sprite)
DestroySprite(sprite);
}
}
// Copy of Rain Dance's function but displays the ion sprite instead
// arg 0: initial step
// arg 1: amount (?)
// arg 2: duration
void AnimTask_CreateIons(u8 taskId)
{
u8 x, y;
if (gTasks[taskId].data[0] == 0)
{
gTasks[taskId].data[1] = gBattleAnimArgs[0];
gTasks[taskId].data[2] = gBattleAnimArgs[1];
gTasks[taskId].data[3] = gBattleAnimArgs[2];
}
gTasks[taskId].data[0]++;
if (gTasks[taskId].data[0] % gTasks[taskId].data[2] == 1)
{
x = Random2() % DISPLAY_WIDTH;
y = Random2() % (DISPLAY_HEIGHT / 2);
CreateSprite(&gIonSpriteTemplate, x, y, 4);
}
if (gTasks[taskId].data[0] == gTasks[taskId].data[3])
DestroyAnimVisualTask(taskId);
}
static void AnimIon(struct Sprite *sprite)
{
sprite->callback = AnimIon_Step;
}
static void AnimIon_Step(struct Sprite *sprite)
{
if (++sprite->data[0] <= 13)
{
sprite->x2++;
sprite->y2 += 4;
}
if (sprite->animEnded)
DestroySprite(sprite);
}

View File

@ -25,6 +25,7 @@ static void AnimTask_MeditateStretchAttacker_Step(u8);
static void AnimTask_Teleport_Step(u8);
static void AnimTask_ImprisonOrbs_Step(u8);
static void AnimTask_SkillSwap_Step(u8);
static void AnimTask_HeartSwap_Step(u8);
static void AnimTask_ExtrasensoryDistortion_Step(u8);
static void AnimTask_TransparentCloneGrowAndShrink_Step(u8);
static void AnimateZenHeadbutt(struct Sprite *sprite);
@ -359,6 +360,18 @@ const struct SpriteTemplate gSkillSwapOrbSpriteTemplate =
.callback = AnimSkillSwapOrb,
};
// Pink version of the Skill Swap orbs
const struct SpriteTemplate gHeartSwapOrbSpriteTemplate =
{
.tileTag = ANIM_TAG_PINKVIO_ORB,
.paletteTag = ANIM_TAG_PINKVIO_ORB,
.oam = &gOamData_AffineNormal_ObjNormal_16x16,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = sAffineAnims_SkillSwapOrb,
.callback = AnimSkillSwapOrb,
};
static const union AffineAnimCmd sAffineAnim_LusterPurgeCircle[] =
{
AFFINEANIMCMD_FRAME(0x20, 0x20, 0, 0),
@ -1001,7 +1014,7 @@ void AnimTask_SkillSwap(u8 taskId)
}
else
{
if (gBattleAnimArgs[0] == 1)
if (gBattleAnimArgs[0] == ANIM_TARGET)
{
task->data[10] = -10;
task->data[11] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_LEFT) + 8;
@ -1023,6 +1036,55 @@ void AnimTask_SkillSwap(u8 taskId)
task->func = AnimTask_SkillSwap_Step;
}
// Copy of Skill Swap's function to get position of the user and target
// arg 0: move target
void AnimTask_HeartSwap(u8 taskId)
{
struct Task *task = &gTasks[taskId];
if (IsContest())
{
if (gBattleAnimArgs[0] == ANIM_TARGET)
{
task->data[10] = -10;
task->data[11] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_RIGHT) - 8;
task->data[12] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_TOP) + 8;
task->data[13] = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_RIGHT) - 8;
task->data[14] = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_TOP) + 8;
}
else
{
task->data[10] = 10;
task->data[11] = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_LEFT) + 8;
task->data[12] = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_BOTTOM) - 8;
task->data[13] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_LEFT) + 8;
task->data[14] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_BOTTOM) - 8;
}
}
else
{
if (gBattleAnimArgs[0] == ANIM_TARGET)
{
task->data[10] = -10;
task->data[11] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_LEFT) + 8;
task->data[12] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_TOP) + 8;
task->data[13] = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_LEFT) + 8;
task->data[14] = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_TOP) + 8;
}
else
{
task->data[10] = 10;
task->data[11] = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_RIGHT) - 8;
task->data[12] = GetBattlerSpriteCoordAttr(gBattleAnimAttacker, BATTLER_COORD_ATTR_BOTTOM) - 8;
task->data[13] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_RIGHT) - 8;
task->data[14] = GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_BOTTOM) - 8;
}
}
task->data[1] = 6;
task->func = AnimTask_HeartSwap_Step;
}
static void AnimTask_SkillSwap_Step(u8 taskId)
{
u8 spriteId;
@ -1057,6 +1119,42 @@ static void AnimTask_SkillSwap_Step(u8 taskId)
}
}
// Copy of Skill Swap's function to vault the series of orbs between the user and target
// CreateSprite modified so it uses the pink orbs instead of the blue/green ones
static void AnimTask_HeartSwap_Step(u8 taskId)
{
u8 spriteId;
struct Task *task = &gTasks[taskId];
switch (task->data[0])
{
case 0:
if (++task->data[1] > 6)
{
task->data[1] = 0;
spriteId = CreateSprite(&gHeartSwapOrbSpriteTemplate, task->data[11], task->data[12], 0);
if (spriteId != MAX_SPRITES)
{
gSprites[spriteId].data[0] = 16;
gSprites[spriteId].data[2] = task->data[13];
gSprites[spriteId].data[4] = task->data[14];
gSprites[spriteId].data[5] = task->data[10];
InitAnimArcTranslation(&gSprites[spriteId]);
StartSpriteAffineAnim(&gSprites[spriteId], task->data[2] & 3);
}
if (++task->data[2] == 12)
task->data[0]++;
}
break;
case 1:
if (++task->data[1] > 17)
DestroyAnimVisualTask(taskId);
break;
}
}
static void AnimSkillSwapOrb(struct Sprite *sprite)
{
if (TranslateAnimHorizontalArc(sprite))

View File

@ -661,7 +661,7 @@ static void OpponentHandleChoosePokemon(u32 battler)
chosenMonId = gSelectedMonPartyId = GetFirstFaintedPartyIndex(battler);
}
// Switching out
else if (*(gBattleStruct->AI_monToSwitchIntoId + battler) == PARTY_SIZE)
else if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE)
{
chosenMonId = GetMostSuitableMonToSwitchInto(battler, TRUE);
if (chosenMonId == PARTY_SIZE)
@ -680,27 +680,27 @@ static void OpponentHandleChoosePokemon(u32 battler)
}
GetAIPartyIndexes(battler, &firstId, &lastId);
for (chosenMonId = (lastId-1); chosenMonId >= firstId; chosenMonId--)
{
if (IsValidForBattle(&gEnemyParty[chosenMonId])
&& chosenMonId != gBattlerPartyIndexes[battler1]
&& chosenMonId != gBattlerPartyIndexes[battler2]
&& (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON)
|| chosenMonId != CalculateEnemyPartyCount() - 1
|| CountAIAliveNonEggMonsExcept(PARTY_SIZE) == pokemonInBattle))
{
break;
}
if (!IsValidForBattle(&gEnemyParty[chosenMonId]))
continue;
if (chosenMonId == gBattlerPartyIndexes[battler1]
|| chosenMonId == gBattlerPartyIndexes[battler2])
continue;
if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON)
&& ((chosenMonId != CalculateEnemyPartyCount() - 1) || CountAIAliveNonEggMonsExcept(PARTY_SIZE) == pokemonInBattle))
continue;
// mon is valid
break;
}
}
*(gBattleStruct->monToSwitchIntoId + battler) = chosenMonId;
gBattleStruct->monToSwitchIntoId[battler] = chosenMonId;
}
else
{
chosenMonId = *(gBattleStruct->AI_monToSwitchIntoId + battler);
*(gBattleStruct->AI_monToSwitchIntoId + battler) = PARTY_SIZE;
*(gBattleStruct->monToSwitchIntoId + battler) = chosenMonId;
chosenMonId = gBattleStruct->AI_monToSwitchIntoId[battler];
gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE;
gBattleStruct->monToSwitchIntoId[battler] = chosenMonId;
}
#if TESTING
TestRunner_Battle_CheckSwitch(battler, chosenMonId);

View File

@ -184,6 +184,7 @@ EWRAM_DATA u16 gLastPrintedMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastLandedMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastHitByType[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastUsedMoveType[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastResultingMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLockedMoves[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gLastUsedMove = 0;
@ -3022,6 +3023,7 @@ static void BattleStartClearSetData(void)
gLastMoves[i] = MOVE_NONE;
gLastLandedMoves[i] = MOVE_NONE;
gLastHitByType[i] = 0;
gLastUsedMoveType[i] = 0;
gLastResultingMoves[i] = MOVE_NONE;
gLastHitBy[i] = 0xFF;
gLockedMoves[i] = MOVE_NONE;
@ -3200,6 +3202,7 @@ void SwitchInClearSetData(u32 battler)
gLastMoves[battler] = MOVE_NONE;
gLastLandedMoves[battler] = MOVE_NONE;
gLastHitByType[battler] = 0;
gLastUsedMoveType[battler] = 0;
gLastResultingMoves[battler] = MOVE_NONE;
gLastPrintedMoves[battler] = MOVE_NONE;
gLastHitBy[battler] = 0xFF;
@ -3333,6 +3336,7 @@ const u8* FaintClearSetData(u32 battler)
gLastMoves[battler] = MOVE_NONE;
gLastLandedMoves[battler] = MOVE_NONE;
gLastHitByType[battler] = 0;
gLastUsedMoveType[battler] = 0;
gLastResultingMoves[battler] = MOVE_NONE;
gLastPrintedMoves[battler] = MOVE_NONE;
gLastHitBy[battler] = 0xFF;
@ -3750,7 +3754,6 @@ static void DoBattleIntro(void)
gBattleStruct->eventsBeforeFirstTurnState = 0;
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers
Ai_InitPartyStruct(); // Save mons party counts, and first 2/4 mons on the battlefield.
// Try to set a status to start the battle with
@ -4070,6 +4073,12 @@ u8 IsRunningFromBattleImpossible(u32 battler)
{
u32 holdEffect, i;
if (FlagGet(B_FLAG_NO_RUNNING))
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CANT_ESCAPE;
return BATTLE_RUN_FORBIDDEN;
}
if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY_E_READER)
holdEffect = gEnigmaBerries[battler].holdEffect;
else
@ -4193,13 +4202,16 @@ static void HandleTurnActionSelectionState(void)
if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart())
&& (BattlerHasAi(battler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE)))
{
AI_DATA->aiCalcInProgress = TRUE;
if (ShouldSwitch(battler, FALSE))
AI_DATA->shouldSwitch |= (1u << battler);
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);
AI_DATA->aiCalcInProgress = FALSE;
}
// fallthrough
case STATE_BEFORE_ACTION_CHOSEN: // Choose an action.
@ -4424,8 +4436,9 @@ static void HandleTurnActionSelectionState(void)
BattleScriptExecute(BattleScript_PrintCantRunFromTrainer);
gBattleCommunication[battler] = STATE_BEFORE_ACTION_CHOSEN;
}
else if (IsRunningFromBattleImpossible(battler) != BATTLE_RUN_SUCCESS
else if ((IsRunningFromBattleImpossible(battler) != BATTLE_RUN_SUCCESS
&& gBattleResources->bufferB[battler][1] == B_ACTION_RUN)
|| (FlagGet(B_FLAG_NO_RUNNING) == TRUE && gBattleResources->bufferB[battler][1] == B_ACTION_RUN))
{
gSelectionBattleScripts[battler] = BattleScript_PrintCantEscapeFromBattle;
gBattleCommunication[battler] = STATE_SELECTION_SCRIPT;
@ -4749,9 +4762,9 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect)
speed *= 2;
else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0)
speed /= 2;
else if (ability == ABILITY_PROTOSYNTHESIS && (gBattleWeather & B_WEATHER_SUN || gBattleStruct->boosterEnergyActivates & (1u << battler)))
else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && ((gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battler)))
speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed;
else if (ability == ABILITY_QUARK_DRIVE && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battler)))
else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battler)))
speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed;
// stat stages

View File

@ -643,7 +643,7 @@ static const u8 sText_HealingWishCameTrue[] = _("The healing wish came true\nfor
static const u8 sText_HealingWishHealed[] = _("{B_ATK_NAME_WITH_PREFIX} regained health!");
static const u8 sText_LunarDanceCameTrue[] = _("{B_ATK_NAME_WITH_PREFIX} became cloaked\nin mystical moonlight!");
static const u8 sText_CursedBodyDisabled[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} was disabled\nby {B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY}!");
static const u8 sText_AttackerAquiredAbility[] = _("{B_ATK_NAME_WITH_PREFIX} acquired\n{B_LAST_ABILITY}!");
static const u8 sText_AttackerAcquiredAbility[] = _("{B_ATK_NAME_WITH_PREFIX} acquired\n{B_ATK_ABILITY}!");
static const u8 sText_TargetStatWontGoHigher[] = _("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1}\nwon't go higher!");
static const u8 sText_PkmnMoveBouncedViaAbility[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE} was\nbounced back by {B_DEF_NAME_WITH_PREFIX}'s\l{B_DEF_ABILITY}!");
static const u8 sText_ImposterTransform[] = _("{B_ATK_NAME_WITH_PREFIX} transformed into\n{B_DEF_NAME_WITH_PREFIX} using {B_LAST_ABILITY}!");
@ -1482,7 +1482,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
[STRINGID_HEALINGWISHHEALED - BATTLESTRINGS_TABLE_START] = sText_HealingWishHealed,
[STRINGID_LUNARDANCECAMETRUE - BATTLESTRINGS_TABLE_START] = sText_LunarDanceCameTrue,
[STRINGID_CUSEDBODYDISABLED - BATTLESTRINGS_TABLE_START] = sText_CursedBodyDisabled,
[STRINGID_ATTACKERACQUIREDABILITY - BATTLESTRINGS_TABLE_START] = sText_AttackerAquiredAbility,
[STRINGID_ATTACKERACQUIREDABILITY - BATTLESTRINGS_TABLE_START] = sText_AttackerAcquiredAbility,
[STRINGID_TARGETABILITYSTATLOWER - BATTLESTRINGS_TABLE_START] = sText_TargetAbilityLoweredStat,
[STRINGID_TARGETSTATWONTGOHIGHER - BATTLESTRINGS_TABLE_START] = sText_TargetStatWontGoHigher,
[STRINGID_PKMNMOVEBOUNCEDABILITY - BATTLESTRINGS_TABLE_START] = sText_PkmnMoveBouncedViaAbility,

View File

@ -6042,12 +6042,14 @@ static void Cmd_moveend(void)
gLastMoves[gBattlerAttacker] = gChosenMove;
RecordKnownMove(gBattlerAttacker, gChosenMove);
gLastResultingMoves[gBattlerAttacker] = gCurrentMove;
gLastUsedMoveType[gBattlerAttacker] = GetMoveType(gCurrentMove);
}
}
else
{
gLastMoves[gBattlerAttacker] = MOVE_UNAVAILABLE;
gLastResultingMoves[gBattlerAttacker] = MOVE_UNAVAILABLE;
gLastUsedMoveType[gBattlerAttacker] = 0;
}
if (!(gHitMarker & HITMARKER_FAINTED(gBattlerTarget)))
@ -6995,126 +6997,53 @@ static void Cmd_openpartyscreen(void)
}
else if (IsDoubleBattle())
{
bool8 hasReplacement_0, hasReplacement_1, hasReplacement_2, hasReplacement_3;
bool32 hasReplacement;
hitmarkerFaintBits = gHitMarker >> 28;
if (1u & hitmarkerFaintBits)
for (i = 0; i < gBattlersCount; i++)
{
battler = 0;
if (HasNoMonsToSwitch(battler, PARTY_SIZE, PARTY_SIZE))
if (((1u << i) & hitmarkerFaintBits))
{
gAbsentBattlerFlags |= 1u << battler;
gHitMarker &= ~HITMARKER_FAINTED(battler);
BtlController_EmitCantSwitch(battler, BUFFER_A);
MarkBattlerForControllerExec(battler);
}
else if (!gSpecialStatuses[battler].faintedHasReplacement)
{
ChooseMonToSendOut(battler, gBattleStruct->monToSwitchIntoId[2]);
gSpecialStatuses[battler].faintedHasReplacement = TRUE;
}
else
{
BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_ONLY, FALSE);
MarkBattlerForControllerExec(battler);
flags |= 1;
if (i > 1 && ((1u << BATTLE_PARTNER(i)) & hitmarkerFaintBits))
continue;
battler = i;
if (HasNoMonsToSwitch(battler, PARTY_SIZE, PARTY_SIZE))
{
gAbsentBattlerFlags |= 1u << battler;
gHitMarker &= ~HITMARKER_FAINTED(battler);
BtlController_EmitCantSwitch(battler, BUFFER_A);
MarkBattlerForControllerExec(battler);
}
else if (!gSpecialStatuses[battler].faintedHasReplacement)
{
ChooseMonToSendOut(battler, gBattleStruct->monToSwitchIntoId[BATTLE_PARTNER(battler)]);
gSpecialStatuses[battler].faintedHasReplacement = TRUE;
}
else if (battler < 2 || (battler > 1 && !(flags & BATTLE_PARTNER(battler))))
{
BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_ONLY, FALSE);
MarkBattlerForControllerExec(battler);
flags |= battler;
}
}
}
if (4u & hitmarkerFaintBits && !(1u & hitmarkerFaintBits))
for (i = 0; i < NUM_BATTLE_SIDES; i++)
{
battler = 2;
if (HasNoMonsToSwitch(battler, PARTY_SIZE, PARTY_SIZE))
if (!(gSpecialStatuses[i].faintedHasReplacement))
{
gAbsentBattlerFlags |= 1u << battler;
gHitMarker &= ~HITMARKER_FAINTED(battler);
BtlController_EmitCantSwitch(battler, BUFFER_A);
MarkBattlerForControllerExec(battler);
}
else if (!gSpecialStatuses[battler].faintedHasReplacement)
{
ChooseMonToSendOut(battler, gBattleStruct->monToSwitchIntoId[0]);
gSpecialStatuses[battler].faintedHasReplacement = TRUE;
}
else if (!(flags & 1))
{
BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_ONLY, FALSE);
MarkBattlerForControllerExec(battler);
}
}
if (2 & hitmarkerFaintBits)
{
battler = 1;
if (HasNoMonsToSwitch(battler, PARTY_SIZE, PARTY_SIZE))
{
gAbsentBattlerFlags |= 1u << battler;
gHitMarker &= ~HITMARKER_FAINTED(battler);
BtlController_EmitCantSwitch(battler, BUFFER_A);
MarkBattlerForControllerExec(battler);
}
else if (!gSpecialStatuses[battler].faintedHasReplacement)
{
ChooseMonToSendOut(battler, gBattleStruct->monToSwitchIntoId[3]);
gSpecialStatuses[battler].faintedHasReplacement = TRUE;
}
else
{
BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_ONLY, FALSE);
MarkBattlerForControllerExec(battler);
flags |= 2;
}
}
if (8 & hitmarkerFaintBits && !(2 & hitmarkerFaintBits))
{
battler = 3;
if (HasNoMonsToSwitch(battler, PARTY_SIZE, PARTY_SIZE))
{
gAbsentBattlerFlags |= 1u << battler;
gHitMarker &= ~HITMARKER_FAINTED(battler);
BtlController_EmitCantSwitch(battler, BUFFER_A);
MarkBattlerForControllerExec(battler);
}
else if (!gSpecialStatuses[battler].faintedHasReplacement)
{
ChooseMonToSendOut(battler, gBattleStruct->monToSwitchIntoId[1]);
gSpecialStatuses[battler].faintedHasReplacement = TRUE;
}
else if (!(flags & 2))
{
BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_ONLY, FALSE);
MarkBattlerForControllerExec(battler);
}
}
hasReplacement = gSpecialStatuses[BATTLE_PARTNER(i)].faintedHasReplacement;
if (!hasReplacement && hitmarkerFaintBits != 0)
{
if (gAbsentBattlerFlags & (1 << i))
battler = BATTLE_PARTNER(i);
else
battler = i;
hasReplacement_0 = gSpecialStatuses[0].faintedHasReplacement;
if (!hasReplacement_0)
{
hasReplacement_2 = gSpecialStatuses[2].faintedHasReplacement;
if (!hasReplacement_2 && hitmarkerFaintBits != 0)
{
if (gAbsentBattlerFlags & 1)
battler = 2;
else
battler = 0;
BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_ONLY, FALSE);
MarkBattlerForControllerExec(battler);
}
}
hasReplacement_1 = gSpecialStatuses[1].faintedHasReplacement;
if (!hasReplacement_1)
{
hasReplacement_3 = gSpecialStatuses[3].faintedHasReplacement;
if (!hasReplacement_3 && hitmarkerFaintBits != 0)
{
if (gAbsentBattlerFlags & 2)
battler = 3;
else
battler = 1;
BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_ONLY, FALSE);
MarkBattlerForControllerExec(battler);
BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_ONLY, FALSE);
MarkBattlerForControllerExec(battler);
}
}
}
}
@ -7127,36 +7056,23 @@ static void Cmd_openpartyscreen(void)
if (IsDoubleBattle())
{
hitmarkerFaintBits = gHitMarker >> 28;
if (4 & hitmarkerFaintBits && 1 & hitmarkerFaintBits)
for (i = 0; i < NUM_BATTLE_SIDES; i++)
{
battler = 2;
if (HasNoMonsToSwitch(battler, gBattleResources->bufferB[0][1], PARTY_SIZE))
if ((1 << BATTLE_PARTNER(i)) & hitmarkerFaintBits && (1 << i) & hitmarkerFaintBits)
{
gAbsentBattlerFlags |= 1u << battler;
gHitMarker &= ~HITMARKER_FAINTED(battler);
BtlController_EmitCantSwitch(battler, BUFFER_A);
MarkBattlerForControllerExec(battler);
}
else if (!gSpecialStatuses[battler].faintedHasReplacement)
{
ChooseMonToSendOut(battler, gBattleStruct->monToSwitchIntoId[0]);
gSpecialStatuses[battler].faintedHasReplacement = TRUE;
}
}
if (8u & hitmarkerFaintBits && hitmarkerFaintBits & 2u)
{
battler = 3;
if (HasNoMonsToSwitch(battler, gBattleResources->bufferB[1][1], PARTY_SIZE))
{
gAbsentBattlerFlags |= 1u << battler;
gHitMarker &= ~HITMARKER_FAINTED(battler);
BtlController_EmitCantSwitch(battler, BUFFER_A);
MarkBattlerForControllerExec(battler);
}
else if (!gSpecialStatuses[battler].faintedHasReplacement)
{
ChooseMonToSendOut(battler, gBattleStruct->monToSwitchIntoId[1]);
gSpecialStatuses[battler].faintedHasReplacement = TRUE;
battler = BATTLE_PARTNER(i);
if (HasNoMonsToSwitch(battler, PARTY_SIZE, PARTY_SIZE))
{
gAbsentBattlerFlags |= (1u << battler);
gHitMarker &= ~(HITMARKER_FAINTED(battler));
BtlController_EmitCantSwitch(battler, BUFFER_A);
MarkBattlerForControllerExec(battler);
}
else if (!gSpecialStatuses[battler].faintedHasReplacement)
{
ChooseMonToSendOut(battler, gBattleStruct->monToSwitchIntoId[i]);
gSpecialStatuses[battler].faintedHasReplacement = TRUE;
}
}
}
gBattlescriptCurrInstr = cmd->nextInstr;
@ -8932,12 +8848,15 @@ u32 GetHighestStatId(u32 battler)
for (i = STAT_DEF; i < NUM_STATS; i++)
{
u16 *statVal = &gBattleMons[battler].attack + (i - 1);
if (*statVal > highestStat)
if (*statVal > highestStat && i != STAT_SPEED)
{
highestStat = *statVal;
highestId = i;
}
}
if (gBattleMons[battler].speed > highestStat)
highestId = STAT_SPEED;
return highestId;
}
@ -9157,6 +9076,7 @@ static void Cmd_various(void)
{
// Roar will fail in a double wild battle when used by the player against one of the two alive wild mons.
// Also when an opposing wild mon uses it againt its partner.
// Also when B_FLAG_NO_RUNNING is enabled.
case VARIOUS_JUMP_IF_ROAR_FAILS:
{
VARIOUS_ARGS(const u8 *jumpInstr);
@ -9169,6 +9089,8 @@ static void Cmd_various(void)
&& GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT
&& GetBattlerSide(gBattlerTarget) == B_SIDE_OPPONENT)
gBattlescriptCurrInstr = cmd->jumpInstr;
else if (FlagGet(B_FLAG_NO_RUNNING))
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
return;
@ -9932,6 +9854,7 @@ static void Cmd_various(void)
if (gBattleMons[gBattlerTarget].ability == ABILITY_NEUTRALIZING_GAS)
gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE;
gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerTarget].ability;
gBattleMons[gBattlerTarget].ability = gBattleStruct->overwrittenAbilities[gBattlerTarget] = ABILITY_SIMPLE;
gBattlescriptCurrInstr = cmd->nextInstr;
}
@ -11483,10 +11406,11 @@ static void Cmd_setmiracleeye(void)
bool8 UproarWakeUpCheck(u8 battler)
{
s32 i;
bool32 hasSoundproof = (B_UPROAR_IGNORE_SOUNDPROOF < GEN_5 && GetBattlerAbility(battler) == ABILITY_SOUNDPROOF);
for (i = 0; i < gBattlersCount; i++)
{
if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || (GetBattlerAbility(battler) == ABILITY_SOUNDPROOF && B_UPROAR_IGNORE_SOUNDPROOF < GEN_5))
if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || hasSoundproof)
continue;
gBattleScripting.battler = i;
@ -12996,60 +12920,122 @@ static void Cmd_settypetorandomresistance(void)
{
CMD_ARGS(const u8 *failInstr);
if (gLastLandedMoves[gBattlerAttacker] == MOVE_NONE
|| gLastLandedMoves[gBattlerAttacker] == MOVE_UNAVAILABLE)
// Before Gen 5 Conversion 2 only worked on a move the attacker was actually hit by.
// This changed later to the last move used by the selected target.
if (B_UPDATED_CONVERSION_2 < GEN_5)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gBattleMoveEffects[gMovesInfo[gLastLandedMoves[gBattlerAttacker]].effect].twoTurnEffect
&& gBattleMons[gLastHitBy[gBattlerAttacker]].status2 & STATUS2_MULTIPLETURNS)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gLastHitByType[gBattlerAttacker] == TYPE_STELLAR || gLastHitByType[gBattlerAttacker] == TYPE_MYSTERY)
{
gBattlescriptCurrInstr = cmd->failInstr;
if (gLastLandedMoves[gBattlerAttacker] == MOVE_NONE
|| gLastLandedMoves[gBattlerAttacker] == MOVE_UNAVAILABLE)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gBattleMoveEffects[gMovesInfo[gLastLandedMoves[gBattlerAttacker]].effect].twoTurnEffect
&& gBattleMons[gLastHitBy[gBattlerAttacker]].status2 & STATUS2_MULTIPLETURNS)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gLastHitByType[gBattlerAttacker] == TYPE_STELLAR || gLastHitByType[gBattlerAttacker] == TYPE_MYSTERY)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else
{
u32 i, resistTypes = 0;
u32 hitByType = gLastHitByType[gBattlerAttacker];
for (i = 0; i < NUMBER_OF_MON_TYPES; i++) // Find all types that resist.
{
switch (GetTypeModifier(hitByType, i))
{
case UQ_4_12(0):
case UQ_4_12(0.5):
resistTypes |= 1u << i;
break;
}
}
while (resistTypes != 0)
{
i = Random() % NUMBER_OF_MON_TYPES;
if (resistTypes & 1u << i)
{
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, i))
{
resistTypes &= ~(1u << i); // Type resists, but the user is already of this type.
}
else
{
SET_BATTLER_TYPE(gBattlerAttacker, i);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, i);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
}
}
}
gBattlescriptCurrInstr = cmd->failInstr;
}
}
else
{
u32 i, resistTypes = 0;
u32 hitByType = gLastHitByType[gBattlerAttacker];
for (i = 0; i < NUMBER_OF_MON_TYPES; i++) // Find all types that resist.
if (gLastResultingMoves[gBattlerTarget] == MOVE_NONE
|| gLastResultingMoves[gBattlerTarget] == MOVE_UNAVAILABLE
|| gLastResultingMoves[gBattlerTarget] == MOVE_STRUGGLE)
{
switch (GetTypeModifier(hitByType, i))
{
case UQ_4_12(0):
case UQ_4_12(0.5):
resistTypes |= 1u << i;
break;
}
gBattlescriptCurrInstr = cmd->failInstr;
}
while (resistTypes != 0)
else if (IsSemiInvulnerable(gBattlerTarget, gCurrentMove))
{
i = Random() % NUMBER_OF_MON_TYPES;
if (resistTypes & (1u << i))
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gLastUsedMoveType[gBattlerTarget] == TYPE_NONE || gLastUsedMoveType[gBattlerTarget] == TYPE_STELLAR || gLastUsedMoveType[gBattlerTarget] == TYPE_MYSTERY)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else
{
u32 i, resistTypes = 0;
for (i = 0; i < NUMBER_OF_MON_TYPES; i++) // Find all types that resist.
{
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, i))
switch (GetTypeModifier(gLastUsedMoveType[gBattlerTarget], i))
{
resistTypes &= ~(1u << i); // Type resists, but the user is already of this type.
}
else
{
SET_BATTLER_TYPE(gBattlerAttacker, i);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, i);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
case UQ_4_12(0):
case UQ_4_12(0.5):
resistTypes |= 1u << i;
break;
}
}
}
gBattlescriptCurrInstr = cmd->failInstr;
while (resistTypes != 0)
{
i = Random() % NUMBER_OF_MON_TYPES;
if (resistTypes & 1u << i)
{
if (IS_BATTLER_OF_TYPE(gBattlerAttacker, i))
{
resistTypes &= ~(1u << i); // Type resists, but the user is already of this type.
}
else
{
SET_BATTLER_TYPE(gBattlerAttacker, i);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, i);
gBattlescriptCurrInstr = cmd->nextInstr;
return;
}
}
}
gBattlescriptCurrInstr = cmd->failInstr;
}
}
}
@ -14349,7 +14335,7 @@ static void Cmd_trycopyability(void)
if (gBattleMons[battler].ability == defAbility
|| defAbility == ABILITY_NONE
|| gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed
|| gAbilitiesInfo[gBattleMons[BATTLE_PARTNER(battler)].ability].cantBeSuppressed
|| (IsBattlerAlive(BATTLE_PARTNER(battler)) && gAbilitiesInfo[gBattleMons[BATTLE_PARTNER(battler)].ability].cantBeSuppressed && gMovesInfo[gCurrentMove].effect == EFFECT_DOODLE)
|| gAbilitiesInfo[defAbility].cantBeCopied)
{
gBattlescriptCurrInstr = cmd->failInstr;
@ -14545,9 +14531,11 @@ static void Cmd_tryswapabilities(void)
}
else
{
u16 abilityAtk = gBattleMons[gBattlerAttacker].ability;
gBattleMons[gBattlerAttacker].ability = gBattleStruct->overwrittenAbilities[gBattlerAttacker] = gBattleMons[gBattlerTarget].ability;
gBattleMons[gBattlerTarget].ability = gBattleStruct->overwrittenAbilities[gBattlerTarget] = abilityAtk;
if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget))
gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerAttacker].ability;
gLastUsedAbility = gBattleMons[gBattlerTarget].ability;
gBattleMons[gBattlerTarget].ability = gBattleStruct->overwrittenAbilities[gBattlerTarget] = gBattleMons[gBattlerAttacker].ability;
gBattleMons[gBattlerAttacker].ability = gBattleStruct->overwrittenAbilities[gBattlerAttacker] = gLastUsedAbility;
gBattlescriptCurrInstr = cmd->nextInstr;
}
@ -15839,6 +15827,7 @@ static void Cmd_tryworryseed(void)
}
else
{
gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerTarget].ability;
gBattleMons[gBattlerTarget].ability = gBattleStruct->overwrittenAbilities[gBattlerTarget] = ABILITY_INSOMNIA;
gBattlescriptCurrInstr = cmd->nextInstr;
}

View File

@ -251,20 +251,7 @@ void HandleAction_UseMove(void)
{
if (moveTarget & MOVE_TARGET_RANDOM)
{
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
{
if (Random() & 1)
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
else
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
}
else
{
if (Random() & 1)
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
else
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
}
gBattlerTarget = SetRandomTarget(gBattlerAttacker);
}
else if (moveTarget & MOVE_TARGET_FOES_AND_ALLY)
{
@ -311,21 +298,7 @@ void HandleAction_UseMove(void)
}
else if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM)
{
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
{
if (Random() & 1)
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
else
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
}
else
{
if (Random() & 1)
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
else
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
}
gBattlerTarget = SetRandomTarget(gBattlerAttacker);
if (gAbsentBattlerFlags & (1u << gBattlerTarget)
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget))
{
@ -450,6 +423,10 @@ bool32 TryRunFromBattle(u32 battler)
u8 pyramidMultiplier;
u8 speedVar;
// If this flag is set, running will never be successful under any circumstances.
if (FlagGet(B_FLAG_NO_RUNNING))
return effect;
if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY_E_READER)
holdEffect = gEnigmaBerries[battler].holdEffect;
else
@ -739,8 +716,6 @@ void HandleAction_ActionFinished(void)
gMoveResultFlags = 0;
gBattleScripting.animTurn = 0;
gBattleScripting.animTargetsHit = 0;
gLastLandedMoves[gBattlerAttacker] = 0;
gLastHitByType[gBattlerAttacker] = 0;
gBattleStruct->dynamicMoveType = 0;
gBattleScripting.moveendState = 0;
gBattleCommunication[3] = 0;
@ -2662,7 +2637,7 @@ u8 DoBattlerEndTurnEffects(void)
for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++)
{
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF)
&& (B_UPROAR_IGNORE_SOUNDPROOF >= GEN_5 || GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF))
{
gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP;
gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE;
@ -4109,12 +4084,125 @@ static void ChooseStatBoostAnimation(u32 battler)
#undef ANIM_STAT_ACC
#undef ANIM_STAT_EVASION
u32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef)
{
enum MoveBlocked effect = MOVE_BLOCKED_BY_NO_ABILITY;
switch (abilityDef)
{
case ABILITY_SOUNDPROOF:
if (gMovesInfo[move].soundMove && !(GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_USER))
effect = MOVE_BLOCKED_BY_SOUNDPROOF_OR_BULLETPROOF;
break;
case ABILITY_BULLETPROOF:
if (gMovesInfo[move].ballisticMove)
effect = MOVE_BLOCKED_BY_SOUNDPROOF_OR_BULLETPROOF;
break;
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (GetBattlerSide(battlerAtk) != GetBattlerSide(battlerDef))
{
u32 priority = AI_DATA->aiCalcInProgress ? GetMovePriority(battlerAtk, move) : GetChosenMovePriority(battlerAtk);
if (priority > 0)
effect = MOVE_BLOCKED_BY_DAZZLING;
}
break;
case ABILITY_GOOD_AS_GOLD:
if (IS_MOVE_STATUS(move))
{
u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move);
if (!(moveTarget & MOVE_TARGET_OPPONENTS_FIELD) && !(moveTarget & MOVE_TARGET_ALL_BATTLERS))
effect = MOVE_BLOCKED_BY_GOOD_AS_GOLD;
}
break;
}
if (!effect)
effect = CanPartnerAbilityBlockMove(battlerAtk, battlerDef, move, GetBattlerAbility(BATTLE_PARTNER(battlerDef)));
return effect;
}
u32 CanPartnerAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef)
{
switch (abilityDef)
{
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (GetBattlerSide(battlerAtk) != GetBattlerSide(battlerDef))
{
s32 priority = AI_DATA->aiCalcInProgress ? GetMovePriority(battlerAtk, move) : GetChosenMovePriority(battlerAtk);
if (priority > 0)
return MOVE_BLOCKED_BY_PARTNER_DAZZLING;
}
break;
}
return MOVE_BLOCKED_BY_NO_ABILITY;
}
u32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType)
{
enum MoveAbsorbed effect = MOVE_ABSORBED_BY_NO_ABILITY;
switch (abilityDef)
{
default:
effect = MOVE_ABSORBED_BY_NO_ABILITY;
break;
case ABILITY_VOLT_ABSORB:
if (moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS)
effect = MOVE_ABSORBED_BY_DRAIN_HP_ABILITY;
break;
case ABILITY_WATER_ABSORB:
case ABILITY_DRY_SKIN:
if (moveType == TYPE_WATER)
effect = MOVE_ABSORBED_BY_DRAIN_HP_ABILITY;
break;
case ABILITY_EARTH_EATER:
if (moveType == TYPE_GROUND)
effect = MOVE_ABSORBED_BY_DRAIN_HP_ABILITY;
break;
case ABILITY_MOTOR_DRIVE:
if (moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS) // Potential bug in singles (might be solved with simu hp reudction)
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
break;
case ABILITY_LIGHTNING_ROD:
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS) // Potential bug in singles (might be solved with simu hp reudction)
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
break;
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_WATER)
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
break;
case ABILITY_SAP_SIPPER:
if (moveType == TYPE_GRASS)
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
break;
case ABILITY_WELL_BAKED_BODY:
if (moveType == TYPE_FIRE)
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
break;
case ABILITY_WIND_RIDER:
if (gMovesInfo[move].windMove && !(GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_USER))
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE && (B_FLASH_FIRE_FROZEN >= GEN_5 || !(gBattleMons[battlerDef].status1 & STATUS1_FREEZE)))
effect = MOVE_ABSORBED_BY_BOOST_FLASH_FIRE;
break;
}
return effect;
}
u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg)
{
u32 effect = 0;
u32 moveType, move;
u32 side;
u32 i, j;
u32 moveType = 0, move = 0;
u32 side = 0;
u32 i = 0, j = 0;
u32 partner = 0;
struct Pokemon *mon;
@ -5208,153 +5296,87 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
}
break;
case ABILITYEFFECT_MOVES_BLOCK:
case ABILITYEFFECT_WOULD_BLOCK:
effect = CanAbilityBlockMove(gBattlerAttacker, battler, move, gLastUsedAbility);
if (effect && gLastUsedAbility != 0xFFFF)
RecordAbilityBattle(battler, gLastUsedAbility);
break;
case ABILITYEFFECT_MOVES_BLOCK:
{
u16 moveTarget = GetBattlerMoveTargetType(battler, move);
effect = CanAbilityBlockMove(gBattlerAttacker, battler, move, gLastUsedAbility);
const u8 * battleScriptBlocksMove = NULL;
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_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)
switch (effect)
{
case MOVE_BLOCKED_BY_SOUNDPROOF_OR_BULLETPROOF:
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
gHitMarker |= HITMARKER_NO_PPDEDUCT;
battleScriptBlocksMove = BattleScript_SoundproofProtected;
}
else if (effect == 2 || effect == 4)
{
if (effect == 4)
break;
case MOVE_BLOCKED_BY_DAZZLING:
case MOVE_BLOCKED_BY_PARTNER_DAZZLING:
if (effect == MOVE_BLOCKED_BY_PARTNER_DAZZLING)
gBattleScripting.battler = BATTLE_PARTNER(battler);
else
gBattleScripting.battler = battler;
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
gHitMarker |= HITMARKER_NO_PPDEDUCT;
battleScriptBlocksMove = BattleScript_DazzlingProtected;
}
else if (effect == 3)
{
break;
case MOVE_BLOCKED_BY_GOOD_AS_GOLD:
battleScriptBlocksMove = BattleScript_GoodAsGoldActivates;
break;
default:
if (GetChosenMovePriority(gBattlerAttacker) > 0
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
&& !(IS_MOVE_STATUS(move) && (gLastUsedAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
{
if (!IsDoubleBattle()
|| !(GetBattlerMoveTargetType(gBattlerAttacker, move) & (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
gBattleScripting.battler = gBattlerAbility = gBattlerTarget;
battleScriptBlocksMove = BattleScript_DarkTypePreventsPrankster;
effect = 1;
}
}
else if (GetChosenMovePriority(gBattlerAttacker) > 0
&& BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
&& !(IS_MOVE_STATUS(move) && (gLastUsedAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove)))
{
if (!IsDoubleBattle() || !(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
gBattleScripting.battler = gBattlerAbility = gBattlerTarget;
battleScriptBlocksMove = BattleScript_DarkTypePreventsPrankster;
effect = 1;
}
if (caseID == ABILITYEFFECT_WOULD_BLOCK)
{
if (effect && gLastUsedAbility != 0xFFFF)
RecordAbilityBattle(battler, gLastUsedAbility);
return effect;
}
else if (effect)
{
if (effect)
gBattlescriptCurrInstr = battleScriptBlocksMove;
}
break;
}
case ABILITYEFFECT_ABSORBING:
break;
case ABILITYEFFECT_WOULD_ABSORB:
if (move != MOVE_NONE)
effect = CanAbilityAbsorbMove(gBattlerAttacker, battler, gLastUsedAbility, move, moveType);
gBattleStruct->pledgeMove = FALSE;
if (effect && gLastUsedAbility != 0xFFFF)
RecordAbilityBattle(battler, gLastUsedAbility);
return effect;
case ABILITYEFFECT_ABSORBING:
{
u8 statId = 0;
u8 statAmount = 1;
switch (gLastUsedAbility)
u32 statId = 0;
u32 statAmount = 1;
effect = CanAbilityAbsorbMove(gBattlerAttacker, battler, gLastUsedAbility, move, moveType);
if (effect)
{
case ABILITY_VOLT_ABSORB:
if (moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS)
effect = 1;
break;
case ABILITY_WATER_ABSORB:
case ABILITY_DRY_SKIN:
if (moveType == TYPE_WATER)
effect = 1;
break;
case ABILITY_MOTOR_DRIVE:
if (moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS)
effect = 2, statId = STAT_SPEED;
break;
case ABILITY_LIGHTNING_ROD:
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS)
effect = 2, statId = STAT_SPATK;
break;
case ABILITY_STORM_DRAIN:
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_WATER)
effect = 2, statId = STAT_SPATK;
break;
case ABILITY_SAP_SIPPER:
if (moveType == TYPE_GRASS)
effect = 2, statId = STAT_ATK;
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE && (B_FLASH_FIRE_FROZEN >= GEN_5 || !(gBattleMons[battler].status1 & STATUS1_FREEZE)))
effect = 3;
break;
case ABILITY_WELL_BAKED_BODY:
if (moveType == TYPE_FIRE)
effect = 2, statId = STAT_DEF, statAmount = 2;
break;
case ABILITY_WIND_RIDER:
if (gMovesInfo[gCurrentMove].windMove && !(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER))
effect = 2, statId = STAT_ATK;
break;
case ABILITY_EARTH_EATER:
if (moveType == TYPE_GROUND)
effect = 1;
break;
switch(gLastUsedAbility)
{
case ABILITY_MOTOR_DRIVE:
statId = STAT_SPEED;
break;
case ABILITY_LIGHTNING_ROD:
case ABILITY_STORM_DRAIN:
statId = STAT_SPATK;
break;
case ABILITY_SAP_SIPPER:
case ABILITY_WIND_RIDER:
statId = STAT_ATK;
break;
case ABILITY_WELL_BAKED_BODY:
statAmount = 2;
statId = STAT_DEF;
break;
}
}
if (caseID == ABILITYEFFECT_WOULD_ABSORB)
{
gBattleStruct->pledgeMove = FALSE;
if (effect && gLastUsedAbility != 0xFFFF)
RecordAbilityBattle(battler, gLastUsedAbility);
return effect;
}
else if (effect == 1) // Drain Hp ability.
switch (effect)
{
case MOVE_ABSORBED_BY_DRAIN_HP_ABILITY:
gBattleStruct->pledgeMove = FALSE;
if (BATTLER_MAX_HP(battler) || (B_HEAL_BLOCKING >= GEN_5 && gStatuses3[battler] & STATUS3_HEAL_BLOCK))
{
@ -5375,9 +5397,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
}
}
else if (effect == 2) // Boost Stat ability;
{
break;
case MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY:
gBattleStruct->pledgeMove = FALSE;
if (!CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN))
{
@ -5397,9 +5418,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (B_ABSORBING_ABILITY_STRING < GEN_5)
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
}
}
else if (effect == 3)
{
break;
case MOVE_ABSORBED_BY_BOOST_FLASH_FIRE:
gBattleStruct->pledgeMove = FALSE;
if (!(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_FLASH_FIRE))
{
@ -5418,10 +5438,11 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
else
gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss;
}
break;
}
if (effect)
gMultiHitCounter = 0; // Prevent multi-hit moves from hitting more than once after move has been absorbed.
}
break;
case ABILITYEFFECT_MOVE_END: // Think contact abilities.
@ -5570,7 +5591,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
break;
}
gLastUsedAbility = gBattleMons[gBattlerAttacker].ability = gBattleStruct->overwrittenAbilities[gBattlerAttacker] = gBattleMons[gBattlerTarget].ability;
gLastUsedAbility = gBattleMons[gBattlerAttacker].ability;
gBattleMons[gBattlerAttacker].ability = gBattleStruct->overwrittenAbilities[gBattlerAttacker] = gBattleMons[gBattlerTarget].ability;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_MummyActivates;
effect++;
@ -6350,7 +6372,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_PROTOSYNTHESIS:
if (!gDisableStructs[battler].weatherAbilityDone && IsBattlerWeatherAffected(battler, B_WEATHER_SUN))
if (!gDisableStructs[battler].weatherAbilityDone
&& (gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
&& !(gBattleStruct->boosterEnergyActivates & (1u << battler)))
{
gDisableStructs[battler].weatherAbilityDone = TRUE;
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
@ -6376,7 +6401,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_QUARK_DRIVE:
if (!gDisableStructs[battler].terrainAbilityDone && IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN))
if (!gDisableStructs[battler].terrainAbilityDone
&& gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
&& !(gBattleStruct->boosterEnergyActivates & (1u << battler)))
{
gDisableStructs[battler].terrainAbilityDone = TRUE;
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
@ -7617,7 +7645,8 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
break;
case HOLD_EFFECT_BOOSTER_ENERGY:
if (!(gBattleStruct->boosterEnergyActivates & (1u << battler))
&& (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !(gBattleWeather & B_WEATHER_SUN))
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
&& (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT))
|| ((GetBattlerAbility(battler) == ABILITY_QUARK_DRIVE) && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN))))
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
@ -7884,7 +7913,8 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
break;
case HOLD_EFFECT_BOOSTER_ENERGY:
if (!(gBattleStruct->boosterEnergyActivates & (1u << battler))
&& (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !(gBattleWeather & B_WEATHER_SUN))
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
&& (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT))
|| ((GetBattlerAbility(battler) == ABILITY_QUARK_DRIVE) && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN))))
{
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
@ -8285,7 +8315,7 @@ void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands
gBattleScriptingCommandsTable[*gBattlescriptCurrInstr]();
}
u32 SetRandomTarget(u32 battler)
u32 SetRandomTarget(u32 battlerAtk)
{
u32 target;
static const u8 targets[2][2] =
@ -8296,13 +8326,13 @@ u32 SetRandomTarget(u32 battler)
if (IsDoubleBattle())
{
target = GetBattlerAtPosition(targets[GetBattlerSide(battler)][Random() % 2]);
target = GetBattlerAtPosition(targets[GetBattlerSide(battlerAtk)][RandomUniform(RNG_RANDOM_TARGET, 0, 1)]);
if (!IsBattlerAlive(target))
target ^= BIT_FLANK;
}
else
{
target = GetBattlerAtPosition(targets[GetBattlerSide(battler)][0]);
target = GetBattlerAtPosition(targets[GetBattlerSide(battlerAtk)][0]);
}
return target;
@ -8613,7 +8643,7 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move)
}
// Only called directly when calculating damage type effectiveness
static bool32 IsBattlerGrounded2(u32 battler, bool32 considerInverse)
static bool32 IsBattlerGroundedInverseCheck(u32 battler, bool32 considerInverse)
{
u32 holdEffect = GetBattlerHoldEffect(battler, TRUE);
@ -8631,7 +8661,7 @@ static bool32 IsBattlerGrounded2(u32 battler, bool32 considerInverse)
return FALSE;
if (holdEffect == HOLD_EFFECT_AIR_BALLOON)
return FALSE;
if (GetBattlerAbility(battler) == ABILITY_LEVITATE)
if ((AI_DATA->aiCalcInProgress ? AI_DATA->abilities[battler] : GetBattlerAbility(battler)) == ABILITY_LEVITATE)
return FALSE;
if (IS_BATTLER_OF_TYPE(battler, TYPE_FLYING) && (!considerInverse || !FlagGet(B_FLAG_INVERSE_BATTLE)))
return FALSE;
@ -8640,7 +8670,7 @@ static bool32 IsBattlerGrounded2(u32 battler, bool32 considerInverse)
bool32 IsBattlerGrounded(u32 battler)
{
return IsBattlerGrounded2(battler, FALSE);
return IsBattlerGroundedInverseCheck(battler, FALSE);
}
bool32 IsBattlerAlive(u32 battler)
@ -9303,8 +9333,9 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
case ABILITY_PROTOSYNTHESIS:
{
u8 atkHighestStat = GetHighestStatId(battlerAtk);
if ((weather & B_WEATHER_SUN || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk))
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK)))
if (((weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk))
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK))
&& !(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
}
break;
@ -9312,16 +9343,17 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
{
u8 atkHighestStat = GetHighestStatId(battlerAtk);
if ((gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk))
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK)))
&& ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK))
&& !(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
}
break;
case ABILITY_ORICHALCUM_PULSE:
if (weather & B_WEATHER_SUN)
if (weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT && IS_MOVE_PHYSICAL(move))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
break;
case ABILITY_HADRON_ENGINE:
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && IS_MOVE_SPECIAL(move))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
break;
case ABILITY_SHARPNESS:
@ -9381,8 +9413,9 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
case ABILITY_PROTOSYNTHESIS:
{
u8 defHighestStat = GetHighestStatId(battlerDef);
if ((weather & B_WEATHER_SUN || gBattleStruct->boosterEnergyActivates & (1u << battlerDef))
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF)))
if (((weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battlerDef))
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF))
&& !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED))
modifier = uq4_12_multiply(modifier, UQ_4_12(0.7));
}
break;
@ -9390,7 +9423,8 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32
{
u8 defHighestStat = GetHighestStatId(battlerDef);
if ((gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battlerDef))
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF)))
&& ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF))
&& !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED))
modifier = uq4_12_multiply(modifier, UQ_4_12(0.7));
}
break;
@ -10361,7 +10395,7 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move
mod = UQ_4_12(1.0);
}
if (gBattleStruct->distortedTypeMatchups & (1u << battlerDef) || (gBattleStruct->aiCalcInProgress && ShouldTeraShellDistortTypeMatchups(move, battlerDef)))
if (gBattleStruct->distortedTypeMatchups & (1u << battlerDef) || (AI_DATA->aiCalcInProgress && ShouldTeraShellDistortTypeMatchups(move, battlerDef)))
{
mod = UQ_4_12(0.5);
if (recordAbilities)
@ -10428,7 +10462,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov
if (B_GLARE_GHOST < GEN_4 && move == MOVE_GLARE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST))
modifier = UQ_4_12(0.0);
}
else if (moveType == TYPE_GROUND && !IsBattlerGrounded2(battlerDef, TRUE) && !(gMovesInfo[move].ignoreTypeIfFlyingAndUngrounded))
else if (moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(battlerDef, TRUE) && !(gMovesInfo[move].ignoreTypeIfFlyingAndUngrounded))
{
modifier = UQ_4_12(0.0);
if (recordAbilities && defAbility == ABILITY_LEVITATE)

View File

@ -2388,6 +2388,8 @@ static u8 GetTreeMutationValue(u8 id)
myMutation.asField.a = tree->mutationA;
myMutation.asField.b = tree->mutationB;
myMutation.asField.unused = 0;
if (myMutation.value == 0) // no mutation
return 0;
return sBerryMutations[myMutation.value - 1][2];
#else
return 0;

View File

@ -87,7 +87,6 @@ void DoBrailleDigEffect(void)
DrawWholeMapView();
PlaySE(SE_BANG);
FlagSet(FLAG_SYS_BRAILLE_DIG);
UnlockPlayerFieldControls();
}
bool8 CheckRelicanthWailord(void)

View File

@ -1514,7 +1514,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
[ABILITY_SLUSH_RUSH] =
{
.name = _("Slush Rush"),
.description = COMPOUND_STRING("Raises Speed in Hail or Snow."),
.description = COMPOUND_STRING("Raises Speed in Hail/Snow."),
.aiRating = 5,
},
@ -2381,7 +2381,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
[ABILITY_TERA_SHELL] =
{
.name = _("Tera Shell"),
.description = COMPOUND_STRING("Resistant to types at full HP."),
.description = COMPOUND_STRING("Resists all at full HP."),
.aiRating = 10,
.cantBeCopied = TRUE,
.cantBeSwapped = TRUE,
@ -2392,7 +2392,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] =
[ABILITY_TERAFORM_ZERO] =
{
.name = _("Teraform Zero"),
.description = COMPOUND_STRING("Removes weather and terrain."),
.description = COMPOUND_STRING("Zeroes weather and terrain."),
.aiRating = 10,
.cantBeCopied = TRUE,
.cantBeSwapped = TRUE,

View File

@ -1465,6 +1465,7 @@ const struct CompressedSpriteSheet gBattleAnimPicTable[] =
{gBattleAnimSpriteGfx_RedExplosion, 0x0800, ANIM_TAG_RED_EXPLOSION},
{gBattleAnimSpriteGfx_Beam, 0x0800, ANIM_TAG_BEAM},
{gBattleAnimSpriteGfx_PurpleChain, 0x1000, ANIM_TAG_PURPLE_CHAIN},
{gBattleAnimSpriteGfx_PinkVioletOrb, 0x0080, ANIM_TAG_PINKVIO_ORB},
};
const struct CompressedSpritePalette gBattleAnimPaletteTable[] =
@ -1931,6 +1932,7 @@ const struct CompressedSpritePalette gBattleAnimPaletteTable[] =
{gBattleAnimSpritePal_RedExplosion, ANIM_TAG_RED_EXPLOSION},
{gBattleAnimSpritePal_Beam, ANIM_TAG_BEAM},
{gBattleAnimSpritePal_PurpleChain, ANIM_TAG_PURPLE_CHAIN},
{gBattleAnimSpritePal_PinkVioletOrb, ANIM_TAG_PINKVIO_ORB},
};
const struct BattleAnimBackground gBattleAnimBackgroundTable[] =

View File

@ -24,9 +24,7 @@ const u32 gRaySceneTakesFlight_Bg_Tilemap[] = INCBIN_U32("graphics/rayquaz
// Scene 3 (RAY_ANIM_DESCENDS)
const u32 gRaySceneDescends_Rayquaza_Gfx[] = INCBIN_U32("graphics/rayquaza_scene/scene_3/rayquaza.4bpp.lz");
// for some reason there are an extra 0xC bytes at the end of the original rayquaza_tail.4bpp, so in order to produce the correct lz,
// we have to cat the bytes at the end with a make rule. not sure why those bytes are there, it may have been a bug in Game Freak's software.
const u32 gRaySceneDescends_RayquazaTail_Gfx[] = INCBIN_U32("graphics/rayquaza_scene/scene_3/rayquaza_tail_fix.4bpp.lz");
const u32 gRaySceneDescends_RayquazaTail_Gfx[] = INCBIN_U32("graphics/rayquaza_scene/scene_3/rayquaza_tail.4bpp.lz");
const u32 gRaySceneDescends_Bg_Gfx[] = INCBIN_U32("graphics/rayquaza_scene/scene_3/bg.4bpp.lz");
const u32 gRaySceneDescends_Light_Gfx[] = INCBIN_U32("graphics/rayquaza_scene/scene_3/light.4bpp.lz"); // uses pal 2 of gRaySceneDescends_Bg_Pal
const u32 gRaySceneDescends_Bg_Pal[] = INCBIN_U32("graphics/rayquaza_scene/scene_3/bg.gbapal.lz");

View File

@ -532,9 +532,9 @@ const struct Item gItemsInfo[] =
.name = _("Sport Ball"),
.price = (I_PRICE < GEN_3 || I_PRICE >= GEN_9) ? 0 : 300,
.description = COMPOUND_STRING(
"A special Ball used\n"
"in the Bug-Catching\n"
"Contest."),
"A special Ball\n"
"used in the Bug-\n"
"Catching Contest."),
.pocket = POCKET_POKE_BALLS,
.type = ITEM_USE_BAG_MENU,
.battleUsage = EFFECT_ITEM_THROW_BALL,
@ -3170,9 +3170,9 @@ const struct Item gItemsInfo[] =
.name = _("Jaw Fossil"),
.price = (I_PRICE >= GEN_7) ? 7000: 1000,
.description = COMPOUND_STRING(
"A piece of a prehis-\n"
"toric Pokémon's\n"
"large jaw."),
"A piece of a\n"
"prehistoric Poké-\n"
"mon's large jaw."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -3186,9 +3186,9 @@ const struct Item gItemsInfo[] =
.name = _("Sail Fossil"),
.price = (I_PRICE >= GEN_7) ? 7000: 1000,
.description = COMPOUND_STRING(
"A piece of a prehis-\n"
"toric Pokémon's\n"
"skin sail."),
"A piece of a\n"
"prehistoric Poké-\n"
"mon's skin sail."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -4163,8 +4163,8 @@ const struct Item gItemsInfo[] =
.price = (I_PRICE >= GEN_7) ? 2000 * TREASURE_FACTOR : 2100,
.description = COMPOUND_STRING(
"Loved by a certain\n"
"Pokémon. Imbued with\n"
"spiritual energy."),
"Pokémon. Imbued\n"
"with spirit energy."),
.pocket = POCKET_ITEMS,
.type = EVO_HELD_ITEM_TYPE,
.fieldUseFunc = EVO_HELD_ITEM_FIELD_FUNC,
@ -4180,8 +4180,8 @@ const struct Item gItemsInfo[] =
.price = (I_PRICE >= GEN_9) ? 3000 : ((I_PRICE >= GEN_7) ? 2000 : 500),
.description = COMPOUND_STRING(
"A mysterious scale\n"
"that evolves certain\n"
"Pokémon. It shines."),
"that evolves a\n"
"certain Pokémon."),
.pocket = POCKET_ITEMS,
.type = EVO_HELD_ITEM_TYPE,
.fieldUseFunc = EVO_HELD_ITEM_FIELD_FUNC,
@ -4214,8 +4214,8 @@ const struct Item gItemsInfo[] =
.name = _("Sachet"),
.price = (I_PRICE >= GEN_7) ? 2000 * TREASURE_FACTOR : 2100,
.description = COMPOUND_STRING(
"A sachet filled with\n"
"perfumes loved by\n"
"A sachet of strong\n"
"perfumes, loved by\n"
"a certain Pokémon."),
.pocket = POCKET_ITEMS,
.type = EVO_HELD_ITEM_TYPE,
@ -4231,9 +4231,9 @@ const struct Item gItemsInfo[] =
.name = _("Oval Stone"),
.price = (I_PRICE >= GEN_7) ? 2000 : 2100,
.description = COMPOUND_STRING(
"Makes a certain\n"
"Pokémon evolve. It's\n"
"shaped like an egg."),
"Peculiar stone\n"
"that evolves a\n"
"certain Pokémon."),
.pocket = POCKET_ITEMS,
.type = EVO_HELD_ITEM_TYPE,
.fieldUseFunc = EVO_HELD_ITEM_FIELD_FUNC,
@ -4743,8 +4743,8 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_PLATE,
.holdEffectParam = 20,
.description = COMPOUND_STRING(
"A stone tablet that\n"
"boosts the power of\n"
"A tablet that ups\n"
"the power of\n"
"Fairy-type moves."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -4939,7 +4939,7 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_MEMORY,
.holdEffectParam = 0,
.description = COMPOUND_STRING(
"A disc with Fighting\n"
"Disc with Fighting\n"
"type data. It swaps\n"
"Silvally's type."),
.pocket = POCKET_ITEMS,
@ -7047,9 +7047,9 @@ const struct Item gItemsInfo[] =
.price = (I_PRICE >= GEN_7) ? 1000 : 10,
.holdEffect = HOLD_EFFECT_QUICK_POWDER,
.description = COMPOUND_STRING(
"An item to be held\n"
"by Ditto. This odd\n"
"powder boosts Speed."),
"A hold item that\n"
"raises the Speed\n"
"of Ditto."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -7126,9 +7126,9 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_ADAMANT_ORB,
.holdEffectParam = 20,
.description = COMPOUND_STRING(
"Boosts the power of\n"
"Dialga's Dragon and\n"
"Steel-type moves."),
"Powers up Dialga's\n"
"Dragon and Steel-\n"
"type moves."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -7144,9 +7144,9 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_LUSTROUS_ORB,
.holdEffectParam = 20,
.description = COMPOUND_STRING(
"Boosts the power of\n"
"Palkia's Dragon and\n"
"Water-type moves."),
"Powers up Palkia's\n"
"Dragon and Water-\n"
"type moves."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -7162,7 +7162,7 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_GRISEOUS_ORB,
.holdEffectParam = 20,
.description = COMPOUND_STRING(
"Powers up Giratina's\n"
"Boosts Giratina's\n"
"Dragon and Ghost-\n"
"type moves."),
.pocket = POCKET_ITEMS,
@ -8101,9 +8101,9 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_CELL_BATTERY,
.holdEffectParam = 0,
.description = COMPOUND_STRING(
"Raises Atk if the\n"
"holder is hit by an\n"
"Electric-type move."),
"Raises Attack if\n"
"the holder is hit by\n"
"an Electric move."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8448,8 +8448,8 @@ const struct Item gItemsInfo[] =
.holdEffectParam = 10,
.description = COMPOUND_STRING(
"A headband that\n"
"boosts the power of\n"
"physical moves."),
"boosts the power\n"
"of physical moves."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8519,9 +8519,9 @@ const struct Item gItemsInfo[] =
.price = (I_PRICE >= GEN_9) ? 50000 : ((I_PRICE >= GEN_7) ? 4000 : 200),
.holdEffect = HOLD_EFFECT_LIFE_ORB,
.description = COMPOUND_STRING(
"Boosts the power of\n"
"moves at the cost\n"
"of some HP per turn."),
"Boosts move power\n"
"but holder loses HP\n"
"with each attack."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8608,9 +8608,9 @@ const struct Item gItemsInfo[] =
.price = (I_PRICE >= GEN_9) ? 20000 : ((I_PRICE >= GEN_7) ? 4000 : 200),
.holdEffect = HOLD_EFFECT_IRON_BALL,
.description = COMPOUND_STRING(
"Cuts Speed and lets\n"
"Flying-types be hit\n"
"by Ground moves."),
"Cuts Speed and\n"
"becomes vulnerable\n"
"to Ground moves."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8657,9 +8657,9 @@ const struct Item gItemsInfo[] =
.price = (I_PRICE >= GEN_9) ? 10000 : ((I_PRICE >= GEN_7) ? 4000 : 200),
.holdEffect = HOLD_EFFECT_BLACK_SLUDGE,
.description = COMPOUND_STRING(
"Gradually restores\n"
"HP of Poison-types.\n"
"Damages others."),
"Restores HP for\n"
"Poison-types.\n"
"Damages all others."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8674,9 +8674,9 @@ const struct Item gItemsInfo[] =
.price = (I_PRICE >= GEN_9) ? 10000 : ((I_PRICE >= GEN_7) ? 4000 : 200),
.holdEffect = HOLD_EFFECT_GRIP_CLAW,
.description = COMPOUND_STRING(
"Makes binding moves\n"
"used by the holder\n"
"go on for 7 turns."),
"A held item that\n"
"extends binding\n"
"moves like Wrap."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8692,8 +8692,8 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_STICKY_BARB,
.description = COMPOUND_STRING(
"Damages the holder\n"
"each turn. May latch\n"
"on to foes."),
"each turn. May\n"
"latch on to foes."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8708,9 +8708,9 @@ const struct Item gItemsInfo[] =
.price = (I_PRICE >= GEN_9) ? 20000 : ((I_PRICE >= GEN_7) ? 4000 : 100),
.holdEffect = HOLD_EFFECT_SHED_SHELL,
.description = COMPOUND_STRING(
"Enables the holder\n"
"to switch out of\n"
"battle without fail."),
"Allows the holder\n"
"to switch out\n"
"without fail."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8727,7 +8727,7 @@ const struct Item gItemsInfo[] =
.holdEffectParam = 30,
.description = COMPOUND_STRING(
"A held item that\n"
"boosts the power of\n"
"ups the power of\n"
"HP-stealing moves."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
@ -8831,9 +8831,9 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_AIR_BALLOON,
.holdEffectParam = 0,
.description = COMPOUND_STRING(
"Elevates the holder\n"
"in the air. If hit,\n"
"this item will burst."),
"Makes the holder\n"
"float but bursts\n"
"if hit by an attack."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8867,9 +8867,9 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_RING_TARGET,
.holdEffectParam = 0,
.description = COMPOUND_STRING(
"Moves that wouldn't\n"
"have effect will\n"
"land on its holder."),
"Moves that usually\n"
"have no effect will\n"
"hit the holder."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8921,9 +8921,9 @@ const struct Item gItemsInfo[] =
.holdEffect = HOLD_EFFECT_WEAKNESS_POLICY,
.holdEffectParam = 0,
.description = COMPOUND_STRING(
"If hit by a Super\n"
"Effective move, ups\n"
"Atk and Sp. Atk."),
"If hit by a super-\n"
"effective move,\n"
"ups Atk and Sp. Atk."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -8974,9 +8974,9 @@ const struct Item gItemsInfo[] =
.price = (I_PRICE >= GEN_9) ? 5000 : ((I_PRICE >= GEN_8) ? 4000 : 300),
.holdEffect = HOLD_EFFECT_ADRENALINE_ORB,
.description = COMPOUND_STRING(
"Boosts Speed if the\n"
"user is intimidated,\n"
"but only one time."),
"This orb boosts\n"
"Speed if the holder\n"
"is intimidated."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -13037,9 +13037,9 @@ const struct Item gItemsInfo[] =
.price = 20000,
.holdEffect = HOLD_EFFECT_COVERT_CLOAK,
.description = COMPOUND_STRING(
"Protects the holder\n"
"from secondary\n"
"move effects."),
"Protects holder\n"
"from additional\n"
"effects of moves."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@ -14004,11 +14004,11 @@ const struct Item gItemsInfo[] =
.description = COMPOUND_STRING(
#if B_X_ITEMS_BUFF >= GEN_7
"Sharply raises\n"
"offenses & defenses\n"
"offense & defense\n"
"during one battle."),
#else
"Raises offenses\n"
"and defenses during\n"
"Raises offense\n"
"and defense during\n"
"one battle."),
#endif
.pocket = POCKET_ITEMS,
@ -14063,9 +14063,9 @@ const struct Item gItemsInfo[] =
.name = _("Pokéshi Doll"),
.price = 2000,
.description = COMPOUND_STRING(
"A wooden toy carved\n"
"in the image of a\n"
"Pokémon. Can be sold."),
"A wooden toy\n"
"resembling a Poké-.\n"
"mon. Can be sold."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,

View File

@ -4505,7 +4505,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.type = TYPE_NORMAL,
.accuracy = 0,
.pp = 30,
.target = MOVE_TARGET_USER,
.target = B_UPDATED_MOVE_DATA >= GEN_5 ? MOVE_TARGET_SELECTED : MOVE_TARGET_USER,
.priority = 0,
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_RECOVER_HP },
@ -14192,8 +14192,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Parabolic Charge"),
.description = COMPOUND_STRING(
"Damages adjacent Pokémon and\n"
"heals up by half of it."),
"Damages adjacent Pokémon\n"
"and heals up by half of it."),
.effect = EFFECT_ABSORB,
.power = B_UPDATED_MOVE_DATA >= GEN_7 ? 65 : 50,
.type = TYPE_ELECTRIC,
@ -16751,7 +16751,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.name = COMPOUND_STRING("Plasma Fists"),
.description = COMPOUND_STRING(
"Hits with electrical fists.\n"
"Normal moves become Electric."),
"Normal moves turn Electric."),
.effect = EFFECT_PLASMA_FISTS,
.power = 100,
.type = TYPE_ELECTRIC,
@ -17110,8 +17110,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Dynamax Cannon"),
.description = COMPOUND_STRING(
"Fires a strong beam. Deals\n"
"2x damage to Dynamaxed foes."),
"Unleashes core energy.\n"
"2x against Dynamaxed foes."),
.effect = EFFECT_DYNAMAX_DOUBLE_DMG,
.power = 100,
.type = TYPE_DRAGON,
@ -18631,8 +18631,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Glacial Lance"),
.description = COMPOUND_STRING(
"Strikes by hurling a blizzard-\n"
"cloaked icicle lance at foes."),
"Hurls a blizzard-cloaked\n"
"icicle lance at foes."),
.effect = EFFECT_HIT,
.power = B_UPDATED_MOVE_DATA >= GEN_9 ? 120 : 130,
.type = TYPE_ICE,
@ -18653,8 +18653,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Astral Barrage"),
.description = COMPOUND_STRING(
"Strikes by sending a frightful\n"
"amount of ghosts at foes."),
"Sends a frightful amount\n"
"of small ghosts at foes."),
.effect = EFFECT_HIT,
.power = 120,
.type = TYPE_GHOST,
@ -20380,8 +20380,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Electro Shot"),
.description = COMPOUND_STRING(
"Absorbs electricity in one turn,\n"
"then attacks next turn."),
"Gathers electricity, then\n"
"fires a high-voltage shot."),
.effect = EFFECT_TWO_TURNS_ATTACK,
.power = 130,
.type = TYPE_ELECTRIC,
@ -20403,8 +20403,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Tera Starstorm"),
.description = COMPOUND_STRING(
"Damages all opponents if user is\n"
"Stellar form Terapagos."),
"In Terapagos's Stellar\n"
"Form, it hits all foes."),
.effect = EFFECT_TERA_STARSTORM,
.power = 120,
.type = TYPE_NORMAL,
@ -20551,8 +20551,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Alluring Voice"),
.description = COMPOUND_STRING(
"Confuses the target if their\n"
"stats were boosted this turn."),
"Confuses foe if its stats\n"
"were boosted this turn."),
.effect = EFFECT_HIT,
.power = 80,
.type = TYPE_FAIRY,

View File

@ -4122,8 +4122,8 @@ const struct SpeciesInfo gSpeciesInfoGen2[] =
.weight = 474,
.description = COMPOUND_STRING(
"A recent study uncovered that the\n"
"number of segments a\n"
"Dudunsparce's body has is determined by the\n"
"number of segments a Dudunsparce's\n"
"body has is determined by the\n"
"Pokémon's genes."),
.pokemonScale = 356,
.pokemonOffset = 17,

View File

@ -4699,9 +4699,9 @@ const struct SpeciesInfo gSpeciesInfoGen3[] =
.weight = 315,
.description = COMPOUND_STRING(
"It uses its amped-up willpower to create\n"
"additional arms for itself. The more it has\n"
"trained its spirit, the more realistic and\n"
"dexterous these self-created arms become."),
"additional arms for itself. The more it\n"
"has trained its spirit, the more realistic\n"
"and dexterous these arms become."),
.pokemonScale = 298,
.pokemonOffset = 5,
.trainerScale = 256,

View File

@ -569,10 +569,10 @@ const struct SpeciesInfo gSpeciesInfoGen4[] =
.height = 17,
.weight = 845,
.description = COMPOUND_STRING(
"The three horns that extend from its beak\n"
"attest to its power. It avoids unnecessary\n"
"disputes, but it will decimate anything\n"
"that threatens its pride."),
"The three horns that extend from its\n"
"beak attest to its power. It avoids\n"
"unnecessary disputes, but it will decimate\n"
"anything that threatens its pride."),
.pokemonScale = 259,
.pokemonOffset = 0,
.trainerScale = 290,
@ -5096,10 +5096,10 @@ const struct SpeciesInfo gSpeciesInfoGen4[] =
.height = 3,
.weight = 3,
.description = COMPOUND_STRING(
"If the convection microwave oven is not\n"
"working properly, then the Rotom inhabiting\n"
"it will become lethargic. It will gleefully\n"
"burn your favorite outfit in mischief."),
"If the convection microwave oven is\n"
"not working properly, then the Rotom\n"
"inhabiting it will become lethargic. It\n"
"makes mischief by turning up the heat."),
.pokemonScale = 530,
.pokemonOffset = 13,
.trainerScale = 256,

View File

@ -10520,10 +10520,10 @@ const struct SpeciesInfo gSpeciesInfoGen5[] =
.height = 14,
.weight = 580,
.description = COMPOUND_STRING(
"It draws in air through its tail, transforms\n"
"it into fire, and uses it like a tongue.\n"
"They burn through Durant's steel bodies\n"
"and consume their insides."),
"It draws in air through its tail,\n"
"transforms it into fire, and uses it like\n"
"a tongue. They burn through Durant's steel\n"
"bodies and consume their insides."),
.pokemonScale = 265,
.pokemonOffset = 2,
.trainerScale = 262,
@ -11360,10 +11360,10 @@ const struct SpeciesInfo gSpeciesInfoGen5[] =
.height = 30,
.weight = 610,
.description = COMPOUND_STRING(
"It pulverizes foes into\n"
"nothingness with showers of devastatingly\n"
"powerful lightning bolts launched from\n"
"the string of orbs on its tail."),
"It pulverizes foes into nothingness\n"
"with showers of devastatingly\n"
"powerful lightning bolts launched\n"
"from the string of orbs on its tail."),
.pokemonScale = 268,
.pokemonOffset = 2,
.trainerScale = 271,
@ -11560,9 +11560,9 @@ const struct SpeciesInfo gSpeciesInfoGen5[] =
.height = 15,
.weight = 680,
.description = COMPOUND_STRING(
"The energy that comes pouring from its tail\n"
"increases the nutrition in the soil, making\n"
"crops grow to great size. It has been\n"
"The energy that comes pouring from its\n"
"tail increases the nutrition in the soil,\n"
"granting bountiful crops. It has been\n"
"hailed as “The Guardian of the Fields.”"),
.pokemonScale = 268,
.pokemonOffset = 2,

View File

@ -650,11 +650,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] =
.categoryName = _("Ninja"),
.height = 15,
.weight = 400,
.description = COMPOUND_STRING(
"It appears and vanishes with a ninja's\n"
"grace. It toys with its enemies using swift\n"
"movements, while slicing them with throwing\n"
"stars made of compressed water."),
.description = gGreninjaPokedexText,
.pokemonScale = 268,
.pokemonOffset = 2,
.trainerScale = 271,
@ -1836,8 +1832,8 @@ const struct SpeciesInfo gSpeciesInfoGen6[] =
{
FLORGES_MISC_INFO(Red, 0),
.description = COMPOUND_STRING(
"This Pokémon creates an\n"
"impressive flower garden in its territory. It\n"
"This Pokémon creates an impressive\n"
"flower garden in its territory. It\n"
"draws forth the power of the red\n"
"flowers around its neck."),
},
@ -4280,8 +4276,8 @@ const struct SpeciesInfo gSpeciesInfoGen6[] =
.height = 17,
.weight = 3341,
.description = COMPOUND_STRING(
"It loathes solitude and is\n"
"extremely clingy-it will fume and run riot if\n"
"It loathes solitude and is extremely\n"
"clingy--it will fume and run riot if\n"
"those dearest to it ever leave its\n"
"side."),
.pokemonScale = 261,
@ -5322,9 +5318,9 @@ const struct SpeciesInfo gSpeciesInfoGen6[] =
.weight = 850,
.description = COMPOUND_STRING(
"They fly around on moonless nights and\n"
"attack careless prey. The ultrasonic waves\n"
"it emits from its ears can reduce a large\n"
"boulder to pebbles."),
"attack careless prey. The ultrasonic\n"
"waves it emits from its ears can reduce\n"
"a large boulder to pebbles."),
.pokemonScale = 268,
.pokemonOffset = 2,
.trainerScale = 271,

View File

@ -3890,8 +3890,8 @@ const struct SpeciesInfo gSpeciesInfoGen7[] =
.height = 5,
.weight = 700,
.description = COMPOUND_STRING(
"It takes control of anyone who puts a hand\n"
"in its mouth, to add to the accumulation\n"
"It takes control of anyone who puts a\n"
"hand in its mouth, to add to the pile\n"
"of its sand-mound body. This Pokémon\n"
"embodies the grudges of the departed."),
.pokemonScale = 432,
@ -6335,10 +6335,10 @@ const struct SpeciesInfo gSpeciesInfoGen7[] =
.height = 38,
.weight = 4600,
.description = COMPOUND_STRING(
"This is its form while it is\n"
"devouring the light of Solgaleo. It pounces\n"
"on foes and then slashes them with\n"
"the claws on its four limbs and back."),
"This is its form while it is devouring\n"
"the light of Solgaleo. It pounces on\n"
"foes and then slashes them with the\n"
"claws on its four limbs and back."),
.pokemonScale = 256,
.pokemonOffset = 3,
.trainerScale = 369,
@ -7125,9 +7125,9 @@ const struct SpeciesInfo gSpeciesInfoGen7[] =
.height = 25,
.weight = 800,
.description = COMPOUND_STRING(
"Revered long ago for its capacity to create\n"
"iron from nothing, for some reason it has\n"
"come back to life after 3,000 years."),
"Revered long ago for its capacity to\n"
"create iron from nothing, for some reason\n"
"it has come back to life after 3,000 years."),
.pokemonScale = 257,
.pokemonOffset = 10,
.trainerScale = 423,

View File

@ -899,8 +899,8 @@ const struct SpeciesInfo gSpeciesInfoGen8[] =
.description = COMPOUND_STRING(
"It will bravely challenge any opponent,\n"
"no matter how powerful. This Pokémon\n"
"benefits from every battle--even a defeat\n"
"increases its strength a bit."),
"benefits from every battle--even a\n"
"defeat increases its strength a bit."),
.pokemonScale = 682,
.pokemonOffset = 24,
.trainerScale = 256,
@ -1339,8 +1339,8 @@ const struct SpeciesInfo gSpeciesInfoGen8[] =
.height = 140,
.weight = 0,
.description = COMPOUND_STRING(
"Its brain has grown to a\n"
"gargantuan size, as has the rest of its body.\n"
"Its brain has grown to a gargantuan\n"
"size, as has the rest of its body.\n"
"This Pokémon's intellect and\n"
"psychic abilities are overpowering."),
.pokemonScale = 491,
@ -3680,9 +3680,9 @@ const struct SpeciesInfo gSpeciesInfoGen8[] =
.weight = 0,
.description = COMPOUND_STRING(
"The heat that comes off a\n"
"Gigantamax Centiskorch may destabilize air\n"
"currents. Sometimes it can even\n"
"cause storms."),
"Gigantamax Centiskorch may\n"
"destabilize air currents. Sometimes\n"
"it can even cause storms."),
.pokemonScale = 275,
.pokemonOffset = 7,
.trainerScale = 256,
@ -4364,9 +4364,9 @@ const struct SpeciesInfo gSpeciesInfoGen8[] =
.weight = 55,
.description = COMPOUND_STRING(
"Through its nose, it sucks in the\n"
"emanations produced by people and Pokémon\n"
"when they feel annoyed. It thrives off\n"
"this negative energy."),
"emanations produced by people and\n"
"Pokémon when they feel annoyed. It\n"
"thrives off this negative energy."),
.pokemonScale = 491,
.pokemonOffset = 12,
.trainerScale = 256,
@ -5667,9 +5667,9 @@ const struct SpeciesInfo gSpeciesInfoGen8[] =
.height = 230,
.weight = 0,
.description = COMPOUND_STRING(
"After this Pokémon has\n"
"Gigantamaxed, its massive nose can utterly\n"
"demolish large structures with a single\n"
"After this Pokémon has Gigantamaxed,\n"
"its massive nose can utterly demolish\n"
"large structures with a single\n"
"smashing blow."),
.pokemonScale = 275,
.pokemonOffset = 7,
@ -6356,8 +6356,8 @@ const struct SpeciesInfo gSpeciesInfoGen8[] =
.weight = 1100,
.description = COMPOUND_STRING(
"Known as a legendary hero, this Pokémon\n"
"absorbs metal particles, transforming them\n"
"into a weapon it uses to battle."),
"absorbs metal particles, transforming\n"
"them into a weapon it uses to battle."),
.pokemonScale = 275,
.pokemonOffset = 7,
.trainerScale = 256,

View File

@ -1035,8 +1035,8 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
.height = 3,
.weight = 25,
.description = COMPOUND_STRING(
"The pads of its paws are\n"
"electricity-discharging organs. Pawmi fires\n"
"The pads of its paws are electricity-\n"
"discharging organs. Pawmi fires\n"
"electricity from its forepaws while\n"
"standing unsteadily on its hind legs."),
.pokemonScale = 356,
@ -4002,8 +4002,8 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
.height = 13,
.weight = 602,
.description = COMPOUND_STRING(
"This Pokémon changes its\n"
"appearance if it hears its allies calling for\n"
"This Pokémon changes its appearance\n"
"if it hears its allies calling for\n"
"help. Palafin will never show\n"
"anybody its moment of transformation."),
.pokemonScale = 356,
@ -4066,8 +4066,8 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
.weight = 974,
.description = COMPOUND_STRING(
"This Pokémon's ancient genes have\n"
"awakened. It is now so\n"
"extraordinarily strong that it can easily lift a\n"
"awakened. It is now so extraordinarily\n"
"strong that it can easily lift a\n"
"cruise ship with one fin."),
.pokemonScale = 356,
.pokemonOffset = 17,

View File

@ -73,9 +73,9 @@ const u8 gGenesectPokedexText[] = _(
// Gen 6 families
const u8 gGreninjaPokedexText[] = _(
"It appears and vanishes with a ninja's\n"
"grace. It toys with its enemies using swift\n"
"movements, while slicing them with throwing\n"
"stars made of compressed water.");
"grace. It toys with its enemies using\n"
"swift movements, while slicing them with\n"
"throwing stars made of compressed water.");
const u8 gScatterbugPokedexText[] = _(
"When under attack from bird Pokémon,\n"
@ -207,7 +207,7 @@ const u8 gKommoOPokedexText[] = _(
// Gen 8 families
const u8 gAlcremieVanillaCreamPokedexText[] = _(
"If Alcremie is content, the secreted cream\n"
"from its hands becomes sweeter and richer."
"from its hands becomes sweeter and richer.\n"
"When it trusts a Trainer, it will treat\n"
"them to berries it's decorated with cream.");
@ -279,8 +279,8 @@ const u8 gOgerponWellspringMaskPokedexText[] = _(
const u8 gOgerponHearthflameMaskPokedexText[] = _(
"This form is the most aggressive,\n"
"bombarding enemies with the\n"
"intensity of flames blazing within a hearth.");
"bombarding enemies with the intensity\n"
"of flames blazing within a hearth.");
const u8 gOgerponCornerstoneMaskPokedexText[] = _(
"In this form, it draws on the power\n"

View File

@ -995,6 +995,8 @@ static void GiveMoveIfItem(struct Pokemon *mon, struct DayCare *daycare)
}
}
STATIC_ASSERT(P_SCATTERBUG_LINE_FORM_BREED == SPECIES_SCATTERBUG_ICY_SNOW || (P_SCATTERBUG_LINE_FORM_BREED >= SPECIES_SCATTERBUG_POLAR && P_SCATTERBUG_LINE_FORM_BREED <= SPECIES_SCATTERBUG_POKEBALL), ScatterbugLineFormBreedMustBeAValidScatterbugForm);
static u16 DetermineEggSpeciesAndParentSlots(struct DayCare *daycare, u8 *parentSlots)
{
u16 i;
@ -1029,6 +1031,8 @@ static u16 DetermineEggSpeciesAndParentSlots(struct DayCare *daycare, u8 *parent
eggSpecies = SPECIES_PHIONE;
else if (GET_BASE_SPECIES_ID(eggSpecies) == SPECIES_ROTOM)
eggSpecies = SPECIES_ROTOM;
else if (GET_BASE_SPECIES_ID(eggSpecies) == SPECIES_SCATTERBUG)
eggSpecies = P_SCATTERBUG_LINE_FORM_BREED;
else if (GET_BASE_SPECIES_ID(eggSpecies) == SPECIES_FURFROU)
eggSpecies = SPECIES_FURFROU;
else if (eggSpecies == SPECIES_SINISTEA_ANTIQUE)

View File

@ -180,7 +180,6 @@ static void SpriteCB_CameraObject(struct Sprite *);
static void CameraObject_Init(struct Sprite *);
static void CameraObject_UpdateMove(struct Sprite *);
static void CameraObject_UpdateFrozen(struct Sprite *);
static const struct ObjectEventTemplate *FindObjectEventTemplateByLocalId(u8, const struct ObjectEventTemplate *, u8);
static void ObjectEventSetSingleMovement(struct ObjectEvent *, struct Sprite *, u8);
static void SetSpriteDataForNormalStep(struct Sprite *, u8, u8);
static void InitSpriteForFigure8Anim(struct Sprite *);
@ -3420,7 +3419,7 @@ static const struct ObjectEventTemplate *GetObjectEventTemplateByLocalIdAndMap(u
return FindObjectEventTemplateByLocalId(localId, templates, count);
}
static const struct ObjectEventTemplate *FindObjectEventTemplateByLocalId(u8 localId, const struct ObjectEventTemplate *templates, u8 count)
const struct ObjectEventTemplate *FindObjectEventTemplateByLocalId(u8 localId, const struct ObjectEventTemplate *templates, u8 count)
{
u8 i;

View File

@ -545,19 +545,13 @@ static void CB2_TradeEvolutionSceneUpdate(void)
static void CreateShedinja(u16 preEvoSpecies, struct Pokemon *mon)
{
u32 data = 0;
#if P_SHEDINJA_BALL >= GEN_4
u16 ball = ITEM_POKE_BALL;
#endif
u16 ball = ITEM_POKE_BALL;
const struct Evolution *evolutions = GetSpeciesEvolutions(preEvoSpecies);
if (evolutions == NULL)
return;
if (evolutions[0].method == EVO_LEVEL_NINJASK && gPlayerPartyCount < PARTY_SIZE
#if P_SHEDINJA_BALL >= GEN_4
&& (CheckBagHasItem(ball, 1))
#endif
)
if (evolutions[0].method == EVO_LEVEL_NINJASK && gPlayerPartyCount < PARTY_SIZE && (P_SHEDINJA_BALL < GEN_4 || CheckBagHasItem(ball, 1)))
{
s32 i;
struct Pokemon *shedinja = &gPlayerParty[gPlayerPartyCount];
@ -567,10 +561,11 @@ static void CreateShedinja(u16 preEvoSpecies, struct Pokemon *mon)
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_NICKNAME, GetSpeciesName(evolutions[1].targetSpecies));
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_HELD_ITEM, &data);
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_MARKINGS, &data);
#if P_SHEDINJA_BALL >= GEN_4
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_POKEBALL, &ball);
RemoveBagItem(ball, 1);
#endif
if (P_SHEDINJA_BALL >= GEN_4)
{
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_POKEBALL, &ball);
RemoveBagItem(ball, 1);
}
for (i = MON_DATA_COOL_RIBBON; i < MON_DATA_COOL_RIBBON + CONTEST_CATEGORIES_COUNT; i++)
SetMonData(&gPlayerParty[gPlayerPartyCount], i, &data);

View File

@ -30,6 +30,7 @@
#include "overworld.h"
#include "party_menu.h"
#include "pokeblock.h"
#include "pokedex.h"
#include "pokemon.h"
#include "pokemon_storage_system.h"
#include "random.h"
@ -4277,6 +4278,55 @@ void PreparePartyForSkyBattle(void)
CompactPartySlots();
}
void GetObjectPosition(u16* xPointer, u16* yPointer, u32 localId, u32 useTemplate)
{
u32 objectId;
struct ObjectEvent* objEvent;
if (useTemplate)
{
const struct ObjectEventTemplate *objTemplate = FindObjectEventTemplateByLocalId(localId, gSaveBlock1Ptr->objectEventTemplates, gMapHeader.events->objectEventCount);
*xPointer = objTemplate->x;
*yPointer = objTemplate->y;
return;
}
objectId = GetObjectEventIdByLocalId(localId);
objEvent = &gObjectEvents[objectId];
*xPointer = objEvent->currentCoords.x - 7;
*yPointer = objEvent->currentCoords.y - 7;
}
bool32 CheckObjectAtXY(u32 x, u32 y)
{
u32 i;
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
{
if (!gObjectEvents[i].active)
continue;
if (gObjectEvents[i].currentCoords.x != x)
continue;
if (gObjectEvents[i].currentCoords.y != y)
continue;
return TRUE;
}
return FALSE;
}
bool32 CheckPartyHasSpecies(u32 givenSpecies)
{
u32 partyIndex;
for (partyIndex = 0; partyIndex < CalculatePlayerPartyCount(); partyIndex++)
if (GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPECIES) == givenSpecies)
return TRUE;
return FALSE;
}
void UseBlankMessageToCancelPokemonPic(void)
{
u8 t = EOS;

View File

@ -1,11 +1,13 @@
#include "global.h"
#include "braille_puzzles.h"
#include "event_scripts.h"
#include "field_effect.h"
#include "field_player_avatar.h"
#include "fldeff.h"
#include "item_use.h"
#include "overworld.h"
#include "party_menu.h"
#include "script.h"
#include "sprite.h"
#include "constants/field_effects.h"
@ -31,8 +33,8 @@ bool8 SetUpFieldMove_Dig(void)
static void FieldCallback_Dig(void)
{
Overworld_ResetStateAfterDigEscRope();
FieldEffectStart(FLDEFF_USE_DIG);
gFieldEffectArguments[0] = GetCursorSelectionMonId();
ScriptContext_SetupScript(EventScript_UseDig);
}
bool8 FldEff_UseDig(void)
@ -53,7 +55,8 @@ static void StartDigFieldEffect(void)
FieldEffectActiveListRemove(FLDEFF_USE_DIG);
if (ShouldDoBrailleDigEffect())
{
DoBrailleDigEffect();
// EventScript_DigSealedChamber handles DoBrailleDigEffect call
ScriptContext_Enable();
}
else
{

View File

@ -1263,6 +1263,9 @@ const u32 gBattleAnimSpriteGfx_XSign[] = INCBIN_U32("graphics/battle_anims/sprit
const u32 gBattleAnimSpriteGfx_BluegreenOrb[] = INCBIN_U32("graphics/battle_anims/sprites/bluegreen_orb.4bpp.lz");
const u32 gBattleAnimSpritePal_BluegreenOrb[] = INCBIN_U32("graphics/battle_anims/sprites/bluegreen_orb.gbapal.lz");
const u32 gBattleAnimSpriteGfx_PinkVioletOrb[] = INCBIN_U32("graphics/battle_anims/sprites/pinkvio_orb.4bpp.lz");
const u32 gBattleAnimSpritePal_PinkVioletOrb[] = INCBIN_U32("graphics/battle_anims/sprites/pinkvio_orb.gbapal.lz");
const u32 gBattleAnimSpriteGfx_PawPrint[] = INCBIN_U32("graphics/battle_anims/sprites/paw_print.4bpp.lz");
const u32 gBattleAnimSpritePal_PawPrint[] = INCBIN_U32("graphics/battle_anims/sprites/paw_print.gbapal.lz");

View File

@ -2367,3 +2367,17 @@ void ResetRecvBuffer(void)
}
}
}
bool32 ShouldCheckForUnionRoom(void)
{
if (OW_UNION_DISABLE_CHECK)
return FALSE;
if (OW_FLAG_MOVE_UNION_ROOM_CHECK == 0)
return TRUE;
if (FlagGet(OW_FLAG_MOVE_UNION_ROOM_CHECK))
return TRUE;
return FALSE;
}

View File

@ -424,6 +424,7 @@ void Overworld_ResetBattleFlagsAndVars(void)
FlagClear(B_SMART_WILD_AI_FLAG);
FlagClear(B_FLAG_NO_BAG_USE);
FlagClear(B_FLAG_NO_CATCHING);
FlagClear(B_FLAG_NO_RUNNING);
FlagClear(B_FLAG_DYNAMAX_BATTLE);
FlagClear(B_FLAG_SKY_BATTLE);
}

View File

@ -4672,7 +4672,7 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc task)
if (canHeal == TRUE)
{
if (hp == 0)
AnimatePartySlot(gPartyMenu.slotId, 1);
AnimatePartySlot(gPartyMenu.slotId, 1);
PartyMenuModifyHP(taskId, gPartyMenu.slotId, 1, GetMonData(mon, MON_DATA_HP) - hp, Task_DisplayHPRestoredMessage);
ResetHPTaskData(taskId, 0, hp);
return;

View File

@ -62,7 +62,7 @@
#include "constants/weather.h"
#include "wild_encounter.h"
#define FRIENDSHIP_EVO_THRESHOLD ((P_FRIENDSHIP_EVO_THRESHOLD >= GEN_9) ? 160 : 220)
#define FRIENDSHIP_EVO_THRESHOLD ((P_FRIENDSHIP_EVO_THRESHOLD >= GEN_8) ? 160 : 220)
struct SpeciesItem
{

View File

@ -32,6 +32,7 @@
#include "mystery_event_script.h"
#include "palette.h"
#include "party_menu.h"
#include "pokedex.h"
#include "pokemon_storage_system.h"
#include "random.h"
#include "overworld.h"
@ -2478,3 +2479,73 @@ void ScriptSetDoubleBattleFlag(struct ScriptContext *ctx)
{
sIsScriptedWildDouble = TRUE;
}
bool8 ScrCmd_removeallitem(struct ScriptContext *ctx)
{
u32 itemId = VarGet(ScriptReadHalfword(ctx));
u32 count = CountTotalItemQuantityInBag(itemId);
gSpecialVar_Result = count;
RemoveBagItem(itemId, count);
return FALSE;
}
bool8 ScrCmd_getobjectxy(struct ScriptContext *ctx)
{
u32 localId = VarGet(ScriptReadHalfword(ctx));
u32 useTemplate = VarGet(ScriptReadHalfword(ctx));
u16 *pX = GetVarPointer(ScriptReadHalfword(ctx));
u16 *pY = GetVarPointer(ScriptReadHalfword(ctx));
GetObjectPosition(pX, pY, localId, useTemplate);
return FALSE;
}
bool8 ScrCmd_checkobjectat(struct ScriptContext *ctx)
{
u32 x = VarGet(ScriptReadHalfword(ctx)) + 7;
u32 y = VarGet(ScriptReadHalfword(ctx)) + 7;
u16 *varPointer = GetVarPointer(ScriptReadHalfword(ctx));
*varPointer = CheckObjectAtXY(x, y);
return FALSE;
}
bool8 Scrcmd_getsetpokedexflag(struct ScriptContext *ctx)
{
u32 speciesId = SpeciesToNationalPokedexNum(VarGet(ScriptReadHalfword(ctx)));
bool32 desiredFlag = VarGet(ScriptReadHalfword(ctx));
gSpecialVar_Result = GetSetPokedexFlag(speciesId, desiredFlag);
if (desiredFlag == FLAG_SET_CAUGHT)
GetSetPokedexFlag(speciesId, FLAG_SET_SEEN);
return FALSE;
}
bool8 Scrcmd_checkspecies(struct ScriptContext *ctx)
{
u32 givenSpecies = VarGet(ScriptReadHalfword(ctx));
gSpecialVar_Result = CheckPartyHasSpecies(givenSpecies);
return FALSE;
}
bool8 Scrcmd_checkspecies_choose(struct ScriptContext *ctx)
{
u32 givenSpecies = VarGet(ScriptReadHalfword(ctx));
gSpecialVar_Result = (GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPECIES) == givenSpecies);
return FALSE;
}
bool8 Scrcmd_getobjectfacingdirection(struct ScriptContext *ctx)
{
u32 objectId = VarGet(ScriptReadHalfword(ctx));
u16 *varPointer = GetVarPointer(ScriptReadHalfword(ctx));
*varPointer = gObjectEvents[GetObjectEventIdByLocalId(objectId)].facingDirection;
return FALSE;
}

View File

@ -3294,6 +3294,9 @@ void InitUnionRoom(void)
{
struct WirelessLink_URoom *data;
if (!ShouldCheckForUnionRoom())
return;
sUnionRoomPlayerName[0] = EOS;
CreateTask(Task_InitUnionRoom, 0);
sWirelessLinkMain.uRoom = sWirelessLinkMain.uRoom; // Needed to match.
@ -3377,6 +3380,9 @@ static void Task_InitUnionRoom(u8 taskId)
bool16 BufferUnionRoomPlayerName(void)
{
if (!ShouldCheckForUnionRoom())
return FALSE;
if (sUnionRoomPlayerName[0] != EOS)
{
StringCopy(gStringVar1, sUnionRoomPlayerName);

View File

@ -221,3 +221,23 @@ SINGLE_BATTLE_TEST("Contrary lowers a stat after using a move which would normal
EXPECT_MUL_EQ(results[1].damageBefore, UQ_4_12(4.0), results[1].damageAfter);
}
}
SINGLE_BATTLE_TEST("Sticky Web raises Speed by 1 for Contrary mon on switch-in")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SNIVY) { Ability(ABILITY_CONTRARY); }
} WHEN {
TURN { MOVE(player, MOVE_STICKY_WEB); }
TURN { SWITCH(opponent, 1); }
TURN {}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, player);
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
MESSAGE("2 sent out Snivy!");
MESSAGE("Foe Snivy was caught in a Sticky Web!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
MESSAGE("Foe Snivy's Speed rose!");
}
}

View File

@ -70,19 +70,19 @@ SINGLE_BATTLE_TEST("Mummy doesn't replace abilities that can't be suppressed")
PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; }
PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; }
PARAMETRIZE { species = SPECIES_WISHIWASHI; ability = ABILITY_SCHOOLING; }
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
PARAMETRIZE { species = SPECIES_MINIOR; ability = ABILITY_SHIELDS_DOWN; }
PARAMETRIZE { species = SPECIES_WISHIWASHI; ability = ABILITY_SCHOOLING; }
PARAMETRIZE { species = SPECIES_MIMIKYU; ability = ABILITY_DISGUISE; }
PARAMETRIZE { species = SPECIES_SILVALLY; ability = ABILITY_RKS_SYSTEM; }
PARAMETRIZE { species = SPECIES_GRENINJA_BATTLE_BOND; ability = ABILITY_BATTLE_BOND; }
PARAMETRIZE { species = SPECIES_ZYGARDE; ability = ABILITY_POWER_CONSTRUCT; }
PARAMETRIZE { species = SPECIES_EISCUE; ability = ABILITY_ICE_FACE; }
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
PARAMETRIZE { species = SPECIES_SILVALLY; ability = ABILITY_RKS_SYSTEM; }
PARAMETRIZE { species = SPECIES_CRAMORANT; ability = ABILITY_GULP_MISSILE; }
PARAMETRIZE { species = SPECIES_EISCUE; ability = ABILITY_ICE_FACE; }
PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; }
PARAMETRIZE { species = SPECIES_CALYREX_SHADOW; ability = ABILITY_AS_ONE_SHADOW_RIDER; }
PARAMETRIZE { species = SPECIES_PALAFIN_ZERO; ability = ABILITY_ZERO_TO_HERO; }
PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_COMMANDER; }
PARAMETRIZE { species = SPECIES_CALYREX_SHADOW; ability = ABILITY_AS_ONE_SHADOW_RIDER; }
PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; }
GIVEN {
PLAYER(SPECIES_YAMASK);

View File

@ -100,6 +100,125 @@ SINGLE_BATTLE_TEST("Protosynthesis activates on switch-in")
}
}
TO_DO_BATTLE_TEST("Protosynthesis activates in sun before Booster Energy");
TO_DO_BATTLE_TEST("Protosynthesis activates even if the Pokémon is holding an Utility Umbrella");
TO_DO_BATTLE_TEST("Protosynthesis doesn't activate if Cloud Nine/Air Lock is on the field");
SINGLE_BATTLE_TEST("Protosynthesis boosts Attack 1st in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Attack(5); Defense(5); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_GROUDON) { Ability(ABILITY_DROUGHT); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("Great Tusk's Attack was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis boosts Defense 2nd in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Attack(4); Defense(5); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_GROUDON) { Ability(ABILITY_DROUGHT); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("Great Tusk's Defense was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis boosts Special Attack 3rd in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Attack(4); Defense(4); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_GROUDON) { Ability(ABILITY_DROUGHT); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("Great Tusk's Sp. Atk was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis boosts Special Defense 4th in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Attack(4); Defense(4); SpAttack(4); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_GROUDON) { Ability(ABILITY_DROUGHT); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("Great Tusk's Sp. Def was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis activates in Sun before Booster Energy")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_BOOSTER_ENERGY); }
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); }
} WHEN {
TURN { SWITCH(player, 1); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
} THEN {
EXPECT_EQ(player->item, ITEM_BOOSTER_ENERGY);
}
}
SINGLE_BATTLE_TEST("Protosynthesis doesn't activate for a transformed battler")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_BOOSTER_ENERGY); }
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); Item(ITEM_BOOSTER_ENERGY); }
} WHEN {
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TRANSFORM); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_PROTOSYNTHESIS);
} THEN {
EXPECT_EQ(player->item, ITEM_BOOSTER_ENERGY);
EXPECT_EQ(opponent->item, ITEM_BOOSTER_ENERGY);
EXPECT_EQ(opponent->ability, ABILITY_PROTOSYNTHESIS);
}
}
SINGLE_BATTLE_TEST("Protosynthesis activates even if the Pokémon is holding an Utility Umbrella")
{
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_UTILITY_UMBRELLA); }
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
}
}
SINGLE_BATTLE_TEST("Protosynthesis doesn't activate if Cloud Nine/Air Lock is on the field")
{
u32 species, ability;
PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; }
PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; }
GIVEN {
PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); }
OPPONENT(species) { Ability(ability); }
} WHEN {
TURN { MOVE(opponent, MOVE_SUNNY_DAY); }
} SCENE {
ABILITY_POPUP(opponent, ability);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
NOT ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
}
}

View File

@ -100,3 +100,109 @@ SINGLE_BATTLE_TEST("Quark Drive activates on switch-in")
MESSAGE("Iron Moth's Sp. Atk was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive activates on Electric Terrain even if not grounded")
{
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_IRON_JUGULIS].types[0] == TYPE_FLYING || gSpeciesInfo[SPECIES_IRON_JUGULIS].types[1] == TYPE_FLYING);
PLAYER(SPECIES_IRON_JUGULIS) { Ability(ABILITY_QUARK_DRIVE); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
}
}
SINGLE_BATTLE_TEST("Quark Drive boosts Attack 1st in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Attack(5); Defense(5); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("Iron Treads's Attack was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive boosts Defense 2nd in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Attack(4); Defense(5); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("Iron Treads's Defense was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive boosts Special Attack 3rd in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Attack(4); Defense(4); SpAttack(5); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("Iron Treads's Sp. Atk was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive boosts Special Defense 4th in case of a stat tie")
{
GIVEN {
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Attack(4); Defense(4); SpAttack(4); SpDefense(5); Speed(5); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Speed(5); }
} WHEN {
TURN { }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("Iron Treads's Sp. Def was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive activates in Electric Terrain before Booster Energy")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Item(ITEM_BOOSTER_ENERGY); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }
} WHEN {
TURN { SWITCH(player, 1); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
} THEN {
EXPECT_EQ(player->item, ITEM_BOOSTER_ENERGY);
}
}
SINGLE_BATTLE_TEST("Quark Drive doesn't activate for a transformed battler")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_IRON_TREADS) { Ability(ABILITY_QUARK_DRIVE); Item(ITEM_BOOSTER_ENERGY); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); Item(ITEM_BOOSTER_ENERGY); }
} WHEN {
TURN { SWITCH(player, 1); MOVE(opponent, MOVE_TRANSFORM); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_QUARK_DRIVE);
} THEN {
EXPECT_EQ(player->item, ITEM_BOOSTER_ENERGY);
EXPECT_EQ(opponent->item, ITEM_BOOSTER_ENERGY);
EXPECT_EQ(opponent->ability, ABILITY_QUARK_DRIVE);
}
}

View File

@ -452,28 +452,18 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if mon would
AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if it can't deal damage to a mon with Wonder Guard 66% of the time")
{
u32 aiOmniscientFlag = 0;
PARAMETRIZE { aiOmniscientFlag = 0; }
PARAMETRIZE { aiOmniscientFlag = AI_FLAG_OMNISCIENT; }
PASSES_RANDOMLY(66, 100, RNG_AI_SWITCH_WONDER_GUARD);
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[0] == TYPE_BUG);
ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].types[1] == TYPE_GHOST);
ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL);
ASSUME(gMovesInfo[MOVE_SHADOW_BALL].type == TYPE_GHOST);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiOmniscientFlag);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_SHEDINJA) { Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SHADOW_BALL); }
} WHEN {
if(aiOmniscientFlag == 0) {
TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_SWITCH(opponent, 1); }
}
else {
TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_SWITCH(opponent, 1); }
}
TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_SWITCH(opponent, 1); }
}
}
@ -496,3 +486,65 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it can't d
TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_SWITCH(opponent, 1); }
}
}
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Toxic'd for at least two turns 50% of the time with more than 1/3 HP remaining")
{
PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_BADLY_POISONED);
GIVEN {
ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE, MOVE_CELEBRATE, MOVE_TOXIC); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
} WHEN {
TURN { MOVE(player, MOVE_TOXIC); EXPECT_MOVE(opponent, MOVE_TACKLE); }
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_TACKLE); }
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
}
}
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Curse'd 50% of the time")
{
PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_CURSED);
GIVEN {
ASSUME(gMovesInfo[MOVE_CURSE].effect == EFFECT_CURSE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_DUSCLOPS) { Moves(MOVE_FIRE_PUNCH, MOVE_CURSE); }
PLAYER(SPECIES_MILOTIC) { Moves(MOVE_WATER_GUN); }
OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_SHADOW_BALL); }
OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_SHADOW_BALL); }
} WHEN {
TURN { MOVE(player, MOVE_CURSE) ; EXPECT_MOVE(opponent, MOVE_SHADOW_BALL); }
TURN { MOVE(player, MOVE_FIRE_PUNCH); EXPECT_SWITCH(opponent, 1); }
}
}
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Nightmare'd 33% of the time")
{
PASSES_RANDOMLY(33, 100, RNG_AI_SWITCH_NIGHTMARE);
GIVEN {
ASSUME(gMovesInfo[MOVE_NIGHTMARE].effect == EFFECT_NIGHTMARE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_GENGAR) { Moves(MOVE_NIGHTMARE); }
OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_SHADOW_BALL); Status1(STATUS1_SLEEP); }
OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_SHADOW_BALL); }
} WHEN {
TURN { MOVE(player, MOVE_NIGHTMARE) ; EXPECT_MOVE(opponent, MOVE_SHADOW_BALL); }
TURN { MOVE(player, MOVE_NIGHTMARE) ; EXPECT_SWITCH(opponent, 1); }
}
}
AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Leech Seed'd 25% of the time")
{
PASSES_RANDOMLY(25, 100, RNG_AI_SWITCH_SEEDED);
GIVEN {
ASSUME(gMovesInfo[MOVE_LEECH_SEED].effect == EFFECT_LEECH_SEED);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING);
PLAYER(SPECIES_WHIMSICOTT) { Moves(MOVE_LEECH_SEED); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); }
} WHEN {
TURN { MOVE(player, MOVE_LEECH_SEED) ; EXPECT_MOVE(opponent, MOVE_TACKLE); }
TURN { MOVE(player, MOVE_LEECH_SEED); EXPECT_SWITCH(opponent, 1); }
}
}

View File

@ -509,6 +509,7 @@ SINGLE_BATTLE_TEST("(TERA) Revelation Dance uses a Stellar-type Pokemon's base t
}
}
#if B_UPDATED_CONVERSION_2 < GEN_5
SINGLE_BATTLE_TEST("(TERA) Conversion2 fails if last hit by a Stellar-type move")
{
GIVEN {
@ -526,6 +527,7 @@ SINGLE_BATTLE_TEST("(TERA) Conversion2 fails if last hit by a Stellar-type move"
MESSAGE("But it failed!");
}
}
#endif
SINGLE_BATTLE_TEST("(TERA) Roost does not remove Flying-type ground immunity when Terastallized into the Stellar type")
{

View File

@ -105,7 +105,31 @@ SINGLE_BATTLE_TEST("Belly Drum's HP cost doesn't trigger effects that trigger on
}
}
SINGLE_BATTLE_TEST("Belly Drum minimizes the user's Attack stat with Contrary", s16 damage)
{
bool32 raiseAttack;
PARAMETRIZE { raiseAttack = FALSE; }
PARAMETRIZE { raiseAttack = TRUE; }
GIVEN {
ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL);
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_CONTRARY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
if (raiseAttack) TURN { MOVE(player, MOVE_BELLY_DRUM); }
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
if (raiseAttack) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BELLY_DRUM, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet cut its own HP and maximized ATTACK!"); // Message unaffected by Contrary
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[1].damage, Q_4_12(4), results[0].damage);
}
}
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");

View File

@ -1,14 +1,207 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last move that hit the user (Gen 3-4)");
TO_DO_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last move used by the target (Gen 5+)");
TO_DO_BATTLE_TEST("Conversion 2's type change considers the type of moves called by other moves");
TO_DO_BATTLE_TEST("Conversion 2's type change considers dynamic type moves"); // Eg. Weather Ball
TO_DO_BATTLE_TEST("Conversion 2's type change considers move types changed by Normalize and Electrify");
TO_DO_BATTLE_TEST("Conversion 2's type change considers move types changed by Normalize");
TO_DO_BATTLE_TEST("Conversion 2's type change considers Struggle to be Normal type (Gen 3-4)");
TO_DO_BATTLE_TEST("Conversion 2 fails if the move used is of typeless damage (Gen 5+)");
TO_DO_BATTLE_TEST("Conversion 2's type change considers status moves (Gen 5+)");
TO_DO_BATTLE_TEST("Conversion 2's type change considers Inverse Battles");
TO_DO_BATTLE_TEST("Conversion 2 fails if the move used is Stellar Type");
#if B_UPDATED_CONVERSION_2 < GEN_5
SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last move that hit the user (Gen 3-4)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_OMINOUS_WIND); MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Ominous Wind!");
// turn 1
ONE_OF {
MESSAGE("Foe Wobbuffet transformed into the Normal type!");
MESSAGE("Foe Wobbuffet transformed into the Dark type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers Struggle to be Normal type (Gen 3-4)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_STRUGGLE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Struggle!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Steel type!");
MESSAGE("Wobbuffet transformed into the Rock type!");
MESSAGE("Wobbuffet transformed into the Ghost type!");
}
}
}
#endif
#if B_UPDATED_CONVERSION_2 >= GEN_5
SINGLE_BATTLE_TEST("Conversion 2 randomly changes the type of the user to a type that resists the last used target's move (Gen 5+)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_OMINOUS_WIND); MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Ominous Wind!");
// turn 1
ONE_OF {
MESSAGE("Foe Wobbuffet transformed into the Normal type!");
MESSAGE("Foe Wobbuffet transformed into the Dark type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers status moves (Gen 5+)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_CURSE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Curse!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Normal type!");
MESSAGE("Wobbuffet transformed into the Dark type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers the type of moves called by other moves")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_OMINOUS_WIND); MOVE(opponent, MOVE_MIRROR_MOVE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Mirror Move!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Normal type!");
MESSAGE("Wobbuffet transformed into the Dark type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers dynamic type moves")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_HAIL); MOVE(opponent, MOVE_WEATHER_BALL); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Weather Ball!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Steel type!");
MESSAGE("Wobbuffet transformed into the Fire type!");
MESSAGE("Wobbuffet transformed into the Water type!");
MESSAGE("Wobbuffet transformed into the Ice type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change considers move types changed by Normalize and Electrify")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_NORMALIZE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_ELECTRIFY); MOVE(opponent, MOVE_POUND); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
TURN { MOVE(player, MOVE_WATER_GUN); MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Electrify!");
MESSAGE("Foe Wobbuffet used Pound!");
// turn 2
ONE_OF {
MESSAGE("Wobbuffet transformed into the Ground type!");
MESSAGE("Wobbuffet transformed into the Dragon type!");
MESSAGE("Wobbuffet transformed into the Grass type!");
MESSAGE("Wobbuffet transformed into the Electric type!");
}
// turn 3
MESSAGE("Wobbuffet used Water Gun!");
ONE_OF {
MESSAGE("Foe Wobbuffet transformed into the Steel type!");
MESSAGE("Foe Wobbuffet transformed into the Rock type!");
MESSAGE("Foe Wobbuffet transformed into the Ghost type!");
}
}
}
SINGLE_BATTLE_TEST("Conversion 2's type change fails targeting Struggle (Gen 5+)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_STRUGGLE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Wobbuffet used Struggle!");
// turn 2
MESSAGE("Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}
SINGLE_BATTLE_TEST("Conversion 2 fails if the move used is of typeless damage (Gen 5+)")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ENTEI);
} WHEN {
TURN { MOVE(opponent, MOVE_BURN_UP); }
TURN { MOVE(opponent, MOVE_REVELATION_DANCE); }
TURN { MOVE(player, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Foe Entei used Burn Up!");
// turn 2
MESSAGE("Foe Entei used Revelation Dance!");
// turn 3
MESSAGE("Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}
#endif
SINGLE_BATTLE_TEST("Conversion 2 fails if the targeted move is Stellar Type")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TERA_BLAST, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_CONVERSION_2); }
} SCENE {
// turn 1
MESSAGE("Wobbuffet used Tera Blast!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player);
// turn 1
MESSAGE("Foe Wobbuffet used Conversion 2!");
MESSAGE("But it failed!");
}
}

View File

@ -35,8 +35,8 @@ DOUBLE_BATTLE_TEST("Doodle can't copy a banned ability")
} WHEN {
TURN { MOVE(playerLeft, MOVE_DOODLE, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOODLE, playerLeft);
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOODLE, playerLeft);
MESSAGE("Wynaut copied Foe Great Tusk's Protosynthesis!");
MESSAGE("Wynaut copied Foe Great Tusk's Protosynthesis!");
}
@ -56,7 +56,7 @@ DOUBLE_BATTLE_TEST("Doodle fails if user has a banned Ability")
} WHEN {
TURN { MOVE(playerLeft, MOVE_DOODLE, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOODLE, playerLeft);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DOODLE, playerLeft);
MESSAGE("But it failed!");
} THEN {
EXPECT(playerLeft->ability == ABILITY_GULP_MISSILE);
@ -74,10 +74,44 @@ DOUBLE_BATTLE_TEST("Doodle fails if partner has a banned Ability")
} WHEN {
TURN { MOVE(playerLeft, MOVE_DOODLE, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOODLE, playerLeft);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DOODLE, playerLeft);
MESSAGE("But it failed!");
} THEN {
EXPECT(playerLeft->ability == ABILITY_SHADOW_TAG);
EXPECT(playerRight->ability == ABILITY_GULP_MISSILE);
}
}
DOUBLE_BATTLE_TEST("Doodle fails if ally's ability can't be suppressed")
{
u32 species, ability;
PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; }
PARAMETRIZE { species = SPECIES_DARMANITAN; ability = ABILITY_ZEN_MODE; }
PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; }
PARAMETRIZE { species = SPECIES_MINIOR; ability = ABILITY_SHIELDS_DOWN; }
PARAMETRIZE { species = SPECIES_WISHIWASHI; ability = ABILITY_SCHOOLING; }
PARAMETRIZE { species = SPECIES_MIMIKYU; ability = ABILITY_DISGUISE; }
PARAMETRIZE { species = SPECIES_GRENINJA_BATTLE_BOND; ability = ABILITY_BATTLE_BOND; }
PARAMETRIZE { species = SPECIES_ZYGARDE; ability = ABILITY_POWER_CONSTRUCT; }
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
PARAMETRIZE { species = SPECIES_SILVALLY; ability = ABILITY_RKS_SYSTEM; }
PARAMETRIZE { species = SPECIES_CRAMORANT; ability = ABILITY_GULP_MISSILE; }
PARAMETRIZE { species = SPECIES_EISCUE; ability = ABILITY_ICE_FACE; }
PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; }
PARAMETRIZE { species = SPECIES_CALYREX_SHADOW; ability = ABILITY_AS_ONE_SHADOW_RIDER; }
PARAMETRIZE { species = SPECIES_PALAFIN_ZERO; ability = ABILITY_ZERO_TO_HERO; }
PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_COMMANDER; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); }
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); }
OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); }
OPPONENT(species) { Ability(ability); }
} WHEN {
TURN { MOVE(opponentLeft, MOVE_DOODLE, target: playerLeft); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DOODLE, opponentLeft);
MESSAGE("But it failed!");
}
}

View File

@ -64,7 +64,7 @@ SINGLE_BATTLE_TEST("King's Shield, Silk Trap and Obstruct protect from damaging
u32 j;
static const u16 protectMoves[][3] =
{ // Move Stat Stages
{MOVE_KINGS_SHIELD, STAT_ATK, 1},
{MOVE_KINGS_SHIELD, STAT_ATK, (B_KINGS_SHIELD_LOWER_ATK >= GEN_8) ? 1 : 2},
{MOVE_SILK_TRAP, STAT_SPEED, 1},
{MOVE_OBSTRUCT, STAT_DEF, 2},
};
@ -99,7 +99,11 @@ SINGLE_BATTLE_TEST("King's Shield, Silk Trap and Obstruct protect from damaging
NOT HP_BAR(opponent);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
if (statId == STAT_ATK) {
#if B_KINGS_SHIELD_LOWER_ATK >= GEN_8
MESSAGE("Wobbuffet's Attack fell!");
#else
MESSAGE("Wobbuffet's Attack harshly fell!");
#endif
} else if (statId == STAT_SPEED) {
MESSAGE("Wobbuffet's Speed fell!");
} else if (statId == STAT_DEF) {

View File

@ -1,23 +1,63 @@
#include "global.h"
#include "test/battle.h"
// Technically also covers Skill Swap and Doodle since both moves use the same command as Role Play
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_ROLE_PLAY].effect == EFFECT_ROLE_PLAY);
}
SINGLE_BATTLE_TEST("Role Play fails if target has a banned ability")
SINGLE_BATTLE_TEST("Role Play copies target's ability")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); }
OPPONENT(SPECIES_CHARMANDER) { Ability(ABILITY_BLAZE); }
}WHEN {
TURN { MOVE(player, MOVE_ROLE_PLAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROLE_PLAY, player);
ABILITY_POPUP(player, ABILITY_TELEPATHY);
} THEN {
EXPECT_EQ(player->ability, ABILITY_BLAZE);
EXPECT_EQ(opponent->ability, ABILITY_BLAZE);
}
}
DOUBLE_BATTLE_TEST("Role Play copies target's current ability even if it changed during that turn")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); }
PLAYER(SPECIES_CHARMANDER) { Ability(ABILITY_BLAZE); }
OPPONENT(SPECIES_BULBASAUR) { Ability(ABILITY_OVERGROW); }
OPPONENT(SPECIES_SQUIRTLE) { Ability(ABILITY_TORRENT); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_ROLE_PLAY, target: opponentLeft); MOVE(opponentRight, MOVE_ROLE_PLAY, target: playerLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROLE_PLAY, playerLeft);
ABILITY_POPUP(playerLeft, ABILITY_TELEPATHY);
if (MOVE_ROLE_PLAY == MOVE_DOODLE)
ABILITY_POPUP(playerRight, ABILITY_BLAZE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_ROLE_PLAY, opponentRight);
ABILITY_POPUP(opponentRight, ABILITY_TORRENT);
NOT ABILITY_POPUP(opponentLeft, ABILITY_OVERGROW); // Already has ability (Doodle)
} THEN {
EXPECT_EQ(playerLeft->ability, ABILITY_OVERGROW);
if (MOVE_ROLE_PLAY == MOVE_DOODLE)
EXPECT_EQ(playerRight->ability, ABILITY_OVERGROW);
EXPECT_EQ(opponentLeft->ability, ABILITY_OVERGROW);
EXPECT_EQ(opponentRight->ability, ABILITY_OVERGROW);
}
}
SINGLE_BATTLE_TEST("Role Play and Doodle fail if target's ability can't be copied'")
{
u32 species, ability;
PARAMETRIZE { species = SPECIES_SHEDINJA; ability = ABILITY_WONDER_GUARD; }
PARAMETRIZE { species = SPECIES_CASTFORM; ability = ABILITY_FORECAST; }
PARAMETRIZE { species = SPECIES_CHERRIM; ability = ABILITY_FLOWER_GIFT; }
PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; }
PARAMETRIZE { species = SPECIES_CHERRIM; ability = ABILITY_FLOWER_GIFT; }
PARAMETRIZE { species = SPECIES_ZORUA; ability = ABILITY_ILLUSION; }
PARAMETRIZE { species = SPECIES_DARMANITAN; ability = ABILITY_ZEN_MODE; }
PARAMETRIZE { species = SPECIES_DITTO; ability = ABILITY_IMPOSTER; }
PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; }
PARAMETRIZE { species = SPECIES_MUK_ALOLA; ability = ABILITY_POWER_OF_ALCHEMY; }
PARAMETRIZE { species = SPECIES_PASSIMIAN; ability = ABILITY_RECEIVER; }
@ -38,29 +78,34 @@ SINGLE_BATTLE_TEST("Role Play fails if target has a banned ability")
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); }
OPPONENT(species) { Ability(ability); }
} WHEN {
TURN { MOVE(player,MOVE_ROLE_PLAY); }
TURN { MOVE(player, MOVE_ROLE_PLAY); }
TURN { MOVE(player, MOVE_DOODLE); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_ROLE_PLAY, player);
MESSAGE("But it failed!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DOODLE, player);
MESSAGE("But it failed!");
}
}
SINGLE_BATTLE_TEST("Role Play fails if user has a banned ability")
SINGLE_BATTLE_TEST("Role Play fails if user's ability can't be suppressed")
{
u32 species, ability;
PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; }
PARAMETRIZE { species = SPECIES_DARMANITAN; ability = ABILITY_ZEN_MODE; }
PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; }
PARAMETRIZE { species = SPECIES_WISHIWASHI; ability = ABILITY_SCHOOLING; }
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
PARAMETRIZE { species = SPECIES_MINIOR; ability = ABILITY_SHIELDS_DOWN; }
PARAMETRIZE { species = SPECIES_WISHIWASHI; ability = ABILITY_SCHOOLING; }
PARAMETRIZE { species = SPECIES_MIMIKYU; ability = ABILITY_DISGUISE; }
PARAMETRIZE { species = SPECIES_SILVALLY; ability = ABILITY_RKS_SYSTEM; }
PARAMETRIZE { species = SPECIES_ZYGARDE; ability = ABILITY_POWER_CONSTRUCT; }
PARAMETRIZE { species = SPECIES_GRENINJA_BATTLE_BOND; ability = ABILITY_BATTLE_BOND; }
PARAMETRIZE { species = SPECIES_EISCUE; ability = ABILITY_ICE_FACE; }
PARAMETRIZE { species = SPECIES_ZYGARDE; ability = ABILITY_POWER_CONSTRUCT; }
PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; }
PARAMETRIZE { species = SPECIES_SILVALLY; ability = ABILITY_RKS_SYSTEM; }
PARAMETRIZE { species = SPECIES_CRAMORANT; ability = ABILITY_GULP_MISSILE; }
PARAMETRIZE { species = SPECIES_EISCUE; ability = ABILITY_ICE_FACE; }
PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; }
PARAMETRIZE { species = SPECIES_CALYREX_SHADOW; ability = ABILITY_AS_ONE_SHADOW_RIDER; }
PARAMETRIZE { species = SPECIES_PALAFIN_ZERO; ability = ABILITY_ZERO_TO_HERO; }
PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_COMMANDER; }
@ -68,9 +113,12 @@ SINGLE_BATTLE_TEST("Role Play fails if user has a banned ability")
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); }
OPPONENT(species) { Ability(ability); }
} WHEN {
TURN { MOVE(opponent,MOVE_ROLE_PLAY); }
TURN { MOVE(opponent, MOVE_ROLE_PLAY); }
TURN { MOVE(opponent, MOVE_DOODLE); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_ROLE_PLAY, opponent);
MESSAGE("But it failed!");
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DOODLE, opponent);
MESSAGE("But it failed!");
}
}

View File

@ -88,6 +88,7 @@ SINGLE_BATTLE_TEST("Shed Tail's HP cost doesn't trigger effects that trigger on
AI_SINGLE_BATTLE_TEST("AI will use Shed Tail to pivot to another mon while in damage stalemate with player")
{
KNOWN_FAILING; // missing AI code
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_WOBBUFFET) { Speed(100); Ability(ABILITY_RUN_AWAY); Moves(MOVE_TACKLE, MOVE_CELEBRATE); }

Some files were not shown because too many files have changed in this diff Show More