Merge branch 'master' of https://github.com/rh-hideout/pokeemerald-expansion into rh-hideout-master

This commit is contained in:
RoamerX 2026-02-07 22:07:24 +08:00
commit af2b69f7e5
198 changed files with 4887 additions and 3089 deletions

View File

@ -633,6 +633,15 @@
"contributions": [
"design"
]
},
{
"login": "ChrispyChris27",
"name": "ChrispyChris27",
"avatar_url": "https://avatars.githubusercontent.com/u/173648816?v=4",
"profile": "https://github.com/ChrispyChris27",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7,

View File

@ -43,9 +43,10 @@ body:
label: Version
description: What version of pokeemerald-expansion are you using?
options:
- 1.14.2 (Latest release)
- 1.14.3 (Latest release)
- master (default, unreleased bugfixes)
- upcoming (Edge)
- 1.14.2
- 1.14.1
- 1.14.0
- 1.13.4

View File

@ -43,9 +43,10 @@ body:
label: Version
description: What version of pokeemerald-expansion are you using?
options:
- 1.14.2 (Latest release)
- 1.14.3 (Latest release)
- master (default, unreleased bugfixes)
- upcoming (Edge)
- 1.14.2
- 1.14.1
- 1.14.0
- 1.13.4

View File

@ -43,9 +43,10 @@ body:
label: Version
description: What version of pokeemerald-expansion are you using?
options:
- 1.14.2 (Latest release)
- 1.14.3 (Latest release)
- master (default, unreleased bugfixes)
- upcoming (Edge)
- 1.14.2
- 1.14.1
- 1.14.0
- 1.13.4

1
.gitignore vendored
View File

@ -52,6 +52,7 @@ src/data/debug_trainers.h
test/battle/trainer_control.h
tools/compresSmol/compresSmol
tools/compresSmol/compresSmolTilemap
tools/aif2pcm/aif2pcm
*.Identifier
*.smol
*.fastSmol

View File

@ -91,6 +91,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SabataLunar"><img src="https://avatars.githubusercontent.com/u/26584469?v=4?s=100" width="100px;" alt="SabataLunar"/><br /><sub><b>SabataLunar</b></sub></a><br /><a href="#design-SabataLunar" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PacFire"><img src="https://avatars.githubusercontent.com/u/108960850?v=4?s=100" width="100px;" alt="PacFire"/><br /><sub><b>PacFire</b></sub></a><br /><a href="#design-PacFire" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ChrispyChris27"><img src="https://avatars.githubusercontent.com/u/173648816?v=4?s=100" width="100px;" alt="ChrispyChris27"/><br /><sub><b>ChrispyChris27</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=ChrispyChris27" title="Code">💻</a></td>
</tr>
</tbody>
<tfoot>

View File

@ -17,7 +17,7 @@
If you use **`pokeemerald-expansion`**, please credit **RHH (Rom Hacking Hideout)**. Optionally, include the version number for clarity.
```
Based off RHH's pokeemerald-expansion 1.14.2 https://github.com/rh-hideout/pokeemerald-expansion/
Based off RHH's pokeemerald-expansion 1.14.3 https://github.com/rh-hideout/pokeemerald-expansion/
```
Please consider [crediting all contributors](CREDITS.md) involved in the project!

View File

@ -351,3 +351,300 @@
createvisualtask AnimTask_IsDoubleBattle, 0
jumprettrue \ptr
.endm
@ createsprite wrappers
@ The arguments are based on the CMD_ARGS of the callback associated with the template.
.macro simple_palette_blend unused_anim_battler=ANIM_ATTACKER, unused_subpriority_offset=2, selector:req, delay:req, initial_blend_y:req, target_blend_y:req, color:req
createsprite gSimplePaletteBlendSpriteTemplate, \unused_anim_battler, \unused_subpriority_offset, \selector, \delay, \initial_blend_y, \target_blend_y, \color
.endm
.macro complex_palette_blend unused_anim_battler=ANIM_ATTACKER, unused_subpriority_offset=2, selector:req, delay:req, num_blends:req, color1:req, blend_y1:req, color2:req, blend_y2:req
createsprite gComplexPaletteBlendSpriteTemplate, \unused_anim_battler, \unused_subpriority_offset, \selector, \delay, \num_blends, \color1, \blend_y1, \color2, \blend_y2
.endm
.macro shake_mon_or_platform unused_anim_battler=ANIM_ATTACKER, unused_subpriority_offset=2, velocity:req, shake_timer:req, shake_duration:req, type:req, battler_selector
.if \type == SHAKE_MON_X || \type == SHAKE_MON_Y
.ifb \battler_selector
.error "battler_selector required for SHAKE_MON_X or SHAKE_MON_Y"
.endif
.else
.ifnb \battler_selector
.warning "unused battler_selector in shake_mon_or_platform"
.endif
.endif
.ifb \battler_selector
createsprite gShakeMonOrPlatformSpriteTemplate, \unused_anim_battler, \unused_subpriority_offset, \velocity, \shake_timer, \shake_duration, \type
.else
createsprite gShakeMonOrPlatformSpriteTemplate, \unused_anim_battler, \unused_subpriority_offset, \velocity, \shake_timer, \shake_duration, \type, \battler_selector
.endif
.endm
.macro create_megahorn_horn_sprite anim_battler:req, subpriority_offset:req, x1:req, y1:req, x2:req, y2:req, duration:req
createsprite gMegahornHornSpriteTemplate, \anim_battler, \subpriority_offset, \x1, \y1, \x2, \y2, \duration
.endm
.macro create_leech_life_needle_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, duration:req
createsprite gLeechLifeNeedleSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \duration
.endm
.macro create_web_thread_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, unk2:req, amplitude:req, targets_both:req
createsprite gWebThreadSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \unk2, \amplitude, \targets_both
.endm
.macro create_string_wrap_sprite anim_battler:req, subpriority_offset:req, x:req, y:req
createsprite gStringWrapSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y
.endm
.macro create_linear_stinger_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, target_x:req, target_y:req, duration:req
createsprite gLinearStingerSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \target_x, \target_y, \duration
.endm
.macro create_pin_missile_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, target_x:req, target_y:req, duration:req, wave_amplitude:req
createsprite gPinMissileSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \target_x, \target_y, \duration, \wave_amplitude
.endm
.macro create_tail_glow_orb_sprite anim_battler:req, subpriority_offset:req, relative_to:req
createsprite gTailGlowOrbSpriteTemplate, \anim_battler, \subpriority_offset, \relative_to
.endm
.macro create_sharp_teeth_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, animation:req, x_velocity:req, y_velocity:req, half_duration:req
createsprite gSharpTeethSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \animation, 256 * \x_velocity, 256 * \y_velocity, \half_duration
.endm
.macro create_clamp_jaw_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, animation:req, x_velocity:req, y_velocity:req, half_duration:req
createsprite gClampJawSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \animation, 256 * \x_velocity, 256 * \y_velocity, \half_duration
.endm
.macro create_tear_drop_sprite anim_battler:req, subpriority_offset:req, relative_to:req, type:req
createsprite gTearDropSpriteTemplate, \anim_battler, \subpriority_offset, \relative_to, \type
.endm
.macro create_claw_slash_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, animation:req
createsprite gClawSlashSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \animation
.endm
.macro create_outrage_flame_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, duration:req, x_velocity:req, y_velocity:req, flicker_duration:req
createsprite gOutrageFlameSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \duration, 256 * \x_velocity, 256 * \y_velocity, \flicker_duration
.endm
.macro create_dragon_breath_fire_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, target_x:req, target_y:req, duration:req
createsprite gDragonBreathFireSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \target_x, \target_y, \duration
.endm
.macro create_dragon_rage_fire_spit_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, target_x:req, target_y:req, duration:req
createsprite gDragonRageFireSpitSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \target_x, \target_y, \duration
.endm
.macro create_dragon_rage_fire_plume_sprite anim_battler:req, subpriority_offset:req, relative_to:req, x:req, y:req
createsprite gDragonRageFirePlumeSpriteTemplate, \anim_battler, \subpriority_offset, \relative_to, \x, \y
.endm
.macro create_dragon_dance_orb_sprite anim_battler:req, subpriority_offset:req, angle:req
createsprite gDragonDanceOrbSpriteTemplate, \anim_battler, \subpriority_offset, 256 * \angle
.endm
.macro create_overheat_flame_sprite anim_battler:req, subpriority_offset:req, speed:req, unk1:req, unk2:req, duration:req, y:req
createsprite gOverheatFlameSpriteTemplate, \anim_battler, \subpriority_offset, \speed, \unk1, \unk2, \duration, \y
.endm
.macro create_sleep_powder_particle_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, duration:req, y_velocity:req, wave_amplitude:req, wave_speed:req
createsprite gSleepPowderParticleSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \duration, 256 * \y_velocity, \wave_amplitude, \wave_speed
.endm
.macro create_stun_spore_particle_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, duration:req, y_velocity:req, wave_amplitude:req, wave_speed:req
createsprite gStunSporeParticleSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \duration, 256 * \y_velocity, \wave_amplitude, \wave_speed
.endm
.macro create_poison_powder_particle_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, duration:req, y_velocity:req, wave_amplitude:req, wave_speed:req
createsprite gPoisonPowderParticleSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \duration, 256 * \y_velocity, \wave_amplitude, \wave_speed
.endm
.macro create_power_absorption_orb_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, duration:req
createsprite gPowerAbsorptionOrbSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \duration
.endm
.macro create_stockpile_absorption_orb_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, duration:req
createsprite gStockpileAbsorptionOrbSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \duration
.endm
.macro create_solar_beam_big_orb_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, duration:req, animation:req
createsprite gSolarBeamBigOrbSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \duration, \animation
.endm
.macro create_absorption_orb_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, wave_amplitude:req, wave_period:req
createsprite gAbsorptionOrbSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \wave_amplitude, \wave_period
.endm
.macro create_hyper_beam_orb_sprite anim_battler:req, subpriority_offset:req
createsprite gHyperBeamOrbSpriteTemplate, \anim_battler, \subpriority_offset
.endm
.macro createleechseedsprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, target_x:req, target_y:req, duration:req, wave_amplitude:req
createsprite gLeechSeedSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \target_x, \target_y, \duration, \wave_amplitude
.endm
.macro create_spore_particle_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, wave_offset:req, duration:req, blend:req
createsprite gSporeParticleSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \wave_offset, \duration, \blend
.endm
.macro create_petal_dance_big_flower_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, target_y:req, duration:req
createsprite gPetalDanceBigFlowerSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \target_y, \duration
.endm
.macro create_petal_dance_small_flower_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, target_y:req, duration:req
createsprite gPetalDanceSmallFlowerSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \target_y, \duration
.endm
.macro create_razor_leaf_particle_sprite anim_battler:req, subpriority_offset:req, upward_delta_x:req, upward_delta_y:req, upward_duration:req
createsprite gRazorLeafParticleSpriteTemplate, \anim_battler, \subpriority_offset, \upward_delta_x, \upward_delta_y, \upward_duration
.endm
.macro create_razor_leaf_cutter_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, target_x:req, target_y:req, duration:req, wave_amplitude:req, target_both:req
createsprite gRazorLeafCutterSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \target_x, \target_y, \duration, \wave_amplitude, \target_both
.endm
.macro create_swift_star_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, target_x:req, target_y:req, duration:req, wave_amplitude:req, target_both:req
createsprite gSwiftStarSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \target_x, \target_y, \duration, \wave_amplitude, \target_both
.endm
.macro create_twister_leaf_sprite anim_battler:req, subpriority_offset:req, duration:req, distance_y:req, wave_period:req, wave_amplitude:req, speed_up_on_frame:req
createsprite gTwisterLeafSpriteTemplate, \anim_battler, \subpriority_offset, \duration, \distance_y, \wave_period, \wave_amplitude, \speed_up_on_frame
.endm
.macro create_constrict_binding_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, affine_animation:req, squeezes:req
createsprite gConstrictBindingSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \affine_animation, \squeezes
.endm
.macro create_mimic_orb_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req
createsprite gMimicOrbSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y
.endm
.macro create_ingrain_root_sprite anim_battler:req, subpriority_offset:req, offset_x:req, offset_y:req, subpriority:req, animation:req, duration:req
createsprite gIngrainRootSpriteTemplate, \anim_battler, \subpriority_offset, \offset_x, \offset_y, \subpriority - 30, \animation, \duration
.endm
.macro create_frenzy_plant_root_sprite anim_battler:req, subpriority_offset:req, interpolate_percent:req, offset_x:req, offset_y:req, subpriority:req, animation:req, duration:req
createsprite gFrenzyPlantRootSpriteTemplate, \anim_battler, \subpriority_offset, \interpolate_percent, \offset_x, \offset_y, \subpriority - 30, \animation, \duration
.endm
.macro create_ingrain_orb_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, velocity_x:req, wave_amplitude:req, duration:req
createsprite gIngrainOrbSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \velocity_x, \wave_amplitude, \duration
.endm
.macro create_present_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, unk2:req, unk3:req, unk4:req
createsprite gPresentSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \unk2, \unk3, \unk4
.endm
.macro create_present_heal_particle_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, velocity_y:req, unused3=1
createsprite gPresentHealParticleSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \velocity_y, \unused3
.endm
.macro create_item_steal_sprite anim_battler:req, subpriority_offset:req, initial_x:req, initial_y:req, unk2, unk3, unk4
createsprite gItemStealSpriteTemplate, \anim_battler, \subpriority_offset, \initial_x, \initial_y, \unk2, \unk3, \unk4
.endm
.macro create_trick_bag_sprite anim_battler:req, subpriority_offset:req, initial_y:req, wave_offset:req
createsprite gTrickBagSpriteTemplate, \anim_battler, \subpriority_offset, \initial_y, \wave_offset
.endm
.macro create_confusion_duck_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, wave_offset:req, wave_period:req, duration:req
createsprite gConfusionDuckSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \wave_offset, \wave_period, \duration
.endm
.macro create_basic_hitsplat_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, relative_to:req, animation:req
createsprite gBasicHitSplatSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \relative_to, \animation
.endm
.macro create_persist_hitsplat_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, relative_to:req, animation:req, duration:req
createsprite gPersistHitSplatSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \relative_to, \animation, \duration
.endm
.macro create_handle_invert_hitsplat_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, relative_to:req, animation:req
createsprite gHandleInvertHitSplatSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \relative_to, \animation
.endm
.macro create_random_pos_hitsplat_sprite anim_battler:req, subpriority_offset:req, relative_to:req, animation
.ifnb \animation
createsprite gRandomPosHitSplatSpriteTemplate, \anim_battler, \subpriority_offset, \relative_to, \animation
.else
createsprite gRandomPosHitSplatSpriteTemplate, \anim_battler, \subpriority_offset, \relative_to, -1
.endif
.endm
.macro create_mon_edge_hitsplat_sprite anim_battler:req, subpriority_offset:req, relative_to:req, x:req, y:req, animation:req
createsprite gMonEdgeHitSplatSpriteTemplate, \anim_battler, \subpriority_offset, \relative_to, \x, \y, \animation
.endm
.macro create_cross_impact_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, relative_to:req, duration:req
createsprite gCrossImpactSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \relative_to, \duration
.endm
.macro create_flashing_hitsplat_sprite anim_battler:req, subpriority_offset:req, x:req, y:req, relative_to:req, animation:req
createsprite gFlashingHitSplatSpriteTemplate, \anim_battler, \subpriority_offset, \x, \y, \relative_to, \animation
.endm
@ createvisualtask wrappers
@ The arguments are based on the CMD_ARGS of the task.
.macro metallic_shine priority=5, permanent:req, color
.ifb \color
createvisualtask AnimTask_MetallicShine, \priority, \permanent, FALSE, RGB_BLACK
.else
createvisualtask AnimTask_MetallicShine, \priority, \permanent, TRUE, \color
.endif
.endm
.macro set_grayscale_pal priority=5, battler:req
createvisualtask AnimTask_SetGrayscaleOrOriginalPal, \priority, \battler, FALSE
.endm
.macro set_original_pal priority=5, battler:req
createvisualtask AnimTask_SetGrayscaleOrOriginalPal, \priority, \battler, TRUE
.endm
.macro attacker_fade_to_invisible priority=2, step_delay:req
createvisualtask AnimTask_AttackerFadeToInvisible, \priority, \step_delay
.endm
.macro attacker_fade_from_invisible priority=2, step_delay:req
createvisualtask AnimTask_AttackerFadeFromInvisible, \priority, \step_delay
.endm
.macro shrink_target_copy priority=5, unk0:req, unk1:req
createvisualtask AnimTask_ShrinkTargetCopy, \priority, \unk0, \unk1
.endm
.macro create_leaf_blade_task priority=5
createvisualtask AnimTask_LeafBlade, \priority
.endm
.macro blend_color_cycle priority=2, selector:req, delay:req, num_blends:req, initial_blend_y:req, target_blend_y:req, color:req
createvisualtask AnimTask_BlendColorCycle, \priority, \selector, \delay, \num_blends, \initial_blend_y, \target_blend_y, \color
.endm
.macro blend_color_cycleexclude priority=2, unk0:req, delay:req, num_blends:req, initial_blend_y:req, target_blend_y:req, color:req
createvisualtask AnimTask_BlendColorCycleExclude, \priority, \unk0, \delay, \num_blends, \initial_blend_y, \target_blend_y, \color
.endm
.macro blend_color_cyclebytag priority=2, tag:req, delay:req, num_blends:req, initial_blend_y:req, target_blend_y:req, color:req
createvisualtask AnimTask_BlendColorCycleByTag, \priority, \tag, \delay, \num_blends, \initial_blend_y, \target_blend_y, \color
.endm
.macro flash_anim_tag_with_color priority=2, tag:req, delay:req, num_blends:req, color1:req, blend_y1:req, color2:req, blend_y2:req
createvisualtask AnimTask_FlashAnimTagWithColor, \priority, \tag, \delay, \num_blends, \color1, \blend_y1, \color2, \blend_y2
.endm
@ NOTE: This function is different on expansion compared to pret
.macro invert_screen_color priority=2, scenery:req
@ NOTE: These generate 0x000 or 0x101 to match, but the code checks for '& 0x100'.
createvisualtask AnimTask_InvertScreenColor, \priority, \scenery
.endm
.macro tint_palettes priority=2, scenery:req, attacker:req, target:req, duration:req, color:req
createvisualtask AnimTask_TintPalettes, \priority, \scenery << 8, \attacker << 8, \target << 8, \duration, \color & 0x1F, (\color >> 5) & 0x1F, (\color >> 10) & 0x1F
.endm
.macro shake_battle_platforms priority=2, x_offset:req, y_offset:req, shakes:req, delay:req
createvisualtask AnimTask_ShakeBattlePlatforms, \priority, \x_offset, \y_offset, \shakes, \delay
.endm

File diff suppressed because it is too large Load Diff

View File

@ -1185,7 +1185,7 @@ BattleScript_EffectPartingShotTrySpAtk:
statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectPartingShotMaybeSwitch
call BattleScript_EffectPartingShotMaybePrintStat
BattleScript_EffectPartingShotMaybeSwitch:
jumpifgenconfiglowerthan CONFIG_PARTING_SHOT_SWITCH, GEN_7, BattleScript_EffectPartingShotSwitch
jumpifgenconfiglowerthan CONFIG_B_PARTING_SHOT_SWITCH, GEN_7, BattleScript_EffectPartingShotSwitch
jumpifbyte CMP_NOT_EQUAL, sB_ANIM_TARGETS_HIT, 0, BattleScript_EffectPartingShotSwitch
goto BattleScript_MoveEnd
@ -1534,7 +1534,7 @@ BattleScript_EffectHitEnemyHealAlly::
BattleScript_EffectDefog::
setstatchanger STAT_EVASION, 1, TRUE
attackcanceler
jumpifgenconfiglowerthan CONFIG_DEFOG_EFFECT_CLEARING, GEN_5, BattleScript_DefogAfterSubstituteCheck
jumpifgenconfiglowerthan CONFIG_B_DEFOG_EFFECT_CLEARING, GEN_5, BattleScript_DefogAfterSubstituteCheck
jumpifsubstituteblocks BattleScript_DefogIfCanClearHazards
BattleScript_DefogAfterSubstituteCheck:
jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_EVASION, MIN_STAT_STAGE, BattleScript_DefogWorks
@ -1542,7 +1542,7 @@ BattleScript_DefogIfCanClearHazards:
trydefog FALSE, BattleScript_ButItFailed
BattleScript_DefogWorks:
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
jumpifgenconfiglowerthan CONFIG_DEFOG_EFFECT_CLEARING, GEN_5, BattleScript_DefogWorksAfterSubstituteCheck
jumpifgenconfiglowerthan CONFIG_B_DEFOG_EFFECT_CLEARING, GEN_5, BattleScript_DefogWorksAfterSubstituteCheck
jumpifsubstituteblocks BattleScript_DefogTryHazardsWithAnim
BattleScript_DefogWorksAfterSubstituteCheck:
statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_DefogTryHazardsWithAnim
@ -2071,7 +2071,7 @@ BattleScript_EffectHealingWish::
setatkhptozero
tryfaintmon BS_ATTACKER
storehealingwish BS_ATTACKER
jumpifgenconfiglowerthan CONFIG_HEALING_WISH_SWITCH, GEN_5, BattleScript_EffectHealingWishGen4
jumpifgenconfiglowerthan CONFIG_B_HEALING_WISH_SWITCH, GEN_5, BattleScript_EffectHealingWishGen4
BattleScript_EffectHealingWishEnd:
moveendall
end
@ -2357,7 +2357,7 @@ BattleScript_TryTailwindAbilitiesLoop_WindPower:
BattleScript_EffectMiracleEye::
attackcanceler
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
jumpifgenconfiglowerthan CONFIG_MIRACLE_EYE_FAIL, GEN_5, BattleScript_MiracleEyeSet
jumpifgenconfiglowerthan CONFIG_B_MIRACLE_EYE_FAIL, GEN_5, BattleScript_MiracleEyeSet
jumpifvolatile BS_TARGET, VOLATILE_MIRACLE_EYE, BattleScript_ButItFailed
BattleScript_MiracleEyeSet:
setvolatile BS_TARGET, VOLATILE_MIRACLE_EYE
@ -3380,7 +3380,7 @@ BattleScript_EffectMeanLook::
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
jumpifvolatile BS_TARGET, VOLATILE_ESCAPE_PREVENTION, BattleScript_ButItFailed
jumpifsubstituteblocks BattleScript_ButItFailed
jumpifgenconfiglowerthan CONFIG_GHOSTS_ESCAPE, GEN_6, BattleScript_EffectMeanLookGen5
jumpifgenconfiglowerthan CONFIG_B_GHOSTS_ESCAPE, GEN_6, BattleScript_EffectMeanLookGen5
jumpiftype BS_TARGET, TYPE_GHOST, BattleScript_ButItFailed
BattleScript_EffectMeanLookGen5:
attackanimation
@ -3393,6 +3393,7 @@ BattleScript_EffectMeanLookGen5:
BattleScript_EffectNightmare::
attackcanceler
jumpifsubstituteblocks BattleScript_ButItFailed
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
jumpifvolatile BS_TARGET, VOLATILE_NIGHTMARE, BattleScript_ButItFailed
jumpifstatus BS_TARGET, STATUS1_SLEEP, BattleScript_NightmareWorked
jumpifability BS_TARGET, ABILITY_COMATOSE, BattleScript_NightmareWorked
@ -3408,7 +3409,7 @@ BattleScript_NightmareWorked::
BattleScript_EffectMinimize::
attackcanceler
setvolatile BS_ATTACKER, VOLATILE_MINIMIZE
jumpifgenconfiglowerthan CONFIG_MINIMIZE_EVASION, GEN_5, BattleScript_EffectMinimizeGen4
jumpifgenconfiglowerthan CONFIG_B_MINIMIZE_EVASION, GEN_5, BattleScript_EffectMinimizeGen4
setstatchanger STAT_EVASION, 2, FALSE
goto BattleScript_EffectStatUpAfterAtkCanceler
BattleScript_EffectMinimizeGen4:
@ -3482,8 +3483,8 @@ BattleScript_EffectSpikes::
BattleScript_EffectForesight::
attackcanceler
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
jumpifgenconfiglowerthan CONFIG_FORESIGHT_FAIL, GEN_3, BattleScript_ForesightFailCheck
jumpifgenconfiglowerthan CONFIG_FORESIGHT_FAIL, GEN_5, BattleScript_ForesightSet
jumpifgenconfiglowerthan CONFIG_B_FORESIGHT_FAIL, GEN_3, BattleScript_ForesightFailCheck
jumpifgenconfiglowerthan CONFIG_B_FORESIGHT_FAIL, GEN_5, BattleScript_ForesightSet
BattleScript_ForesightFailCheck:
jumpifvolatile BS_TARGET, VOLATILE_FORESIGHT, BattleScript_ButItFailed
BattleScript_ForesightSet:
@ -3767,6 +3768,7 @@ BattleScript_EffectBellyDrum::
BattleScript_EffectPsychUp::
attackcanceler
accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE
copyfoestats
attackanimation
waitanimation
@ -3793,7 +3795,7 @@ BattleScript_EffectFutureSight::
goto BattleScript_MoveEnd
BattleScript_EffectTeleport::
jumpifgenconfiglowerthan CONFIG_TELEPORT_BEHAVIOR, GEN_8, BattleScript_EffectTeleportGen7
jumpifgenconfiglowerthan CONFIG_B_TELEPORT_BEHAVIOR, GEN_8, BattleScript_EffectTeleportGen7
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_EffectBatonPass
jumpifside BS_ATTACKER, B_SIDE_PLAYER, BattleScript_EffectBatonPass
goto BattleScript_DoEffectTeleport
@ -3812,7 +3814,7 @@ BattleScript_DoEffectTeleport::
goto BattleScript_MoveEnd
BattleScript_EffectBeatUp::
jumpifgenconfiglowerthan CONFIG_BEAT_UP, GEN_5, BattleScript_EffectBeatUpGen3
jumpifgenconfiglowerthan CONFIG_B_BEAT_UP, GEN_5, BattleScript_EffectBeatUpGen3
goto BattleScript_EffectHit
BattleScript_EffectBeatUpGen3:
@ -5972,7 +5974,7 @@ BattleScript_CudChewActivates::
end2
BattleScript_ApplyDisguiseFormChangeHPLoss::
jumpifgenconfiglowerthan CONFIG_DISGUISE_HP_LOSS, GEN_8, BattleScript_ApplyDisguiseFormChangeHPLossReturn
jumpifgenconfiglowerthan CONFIG_B_DISGUISE_HP_LOSS, GEN_8, BattleScript_ApplyDisguiseFormChangeHPLossReturn
healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE
datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE
BattleScript_ApplyDisguiseFormChangeHPLossReturn:
@ -7336,7 +7338,7 @@ BattleScript_WeakArmorDefPrintString:
printstring STRINGID_TARGETABILITYSTATLOWER
waitmessage B_WAIT_TIME_LONG
BattleScript_WeakArmorActivatesSpeed:
jumpifgenconfiglowerthan CONFIG_WEAK_ARMOR_SPEED, GEN_7, BattleScript_WeakArmorSetSpeedGen6
jumpifgenconfiglowerthan CONFIG_B_WEAK_ARMOR_SPEED, GEN_7, BattleScript_WeakArmorSetSpeedGen6
setstatchanger STAT_SPEED, 2, FALSE
goto BattleScript_WeakArmorDoSpeed
BattleScript_WeakArmorSetSpeedGen6:

View File

@ -44,6 +44,7 @@
- [Vs. Seeker](tutorials/vs_seeker.md)
- [Changelog](./CHANGELOG.md)
- [1.14.x]()
- [Version 1.14.3](changelogs/1.14.x/1.14.3.md)
- [Version 1.14.2](changelogs/1.14.x/1.14.2.md)
- [Version 1.14.1](changelogs/1.14.x/1.14.1.md)
- [Version 1.14.0](changelogs/1.14.x/1.14.0.md)

View File

@ -0,0 +1,170 @@
```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.14.3
`.
```
## 🧬 General 🧬
### Changed
* Misc style and whitespace cleanup by @grintoul1 in [#8681](https://github.com/rh-hideout/pokeemerald-expansion/pull/8681)
* Disable L button config (throw ball shortcut or move description) when there is overlap with L=A option by @FosterProgramming in [#8332](https://github.com/rh-hideout/pokeemerald-expansion/pull/8332)
* Update CONTRIBUTING.md by @pkmnsnfrn in [#8879](https://github.com/rh-hideout/pokeemerald-expansion/pull/8879)
* Deleted unnecessary files by @Bassoonian in [#8899](https://github.com/rh-hideout/pokeemerald-expansion/pull/8899)
* Fix Metronome bans by @amiosi in [#8834](https://github.com/rh-hideout/pokeemerald-expansion/pull/8834)
* Move CMD_ARGS to battle_script_commands by @hedara90 in [#8974](https://github.com/rh-hideout/pokeemerald-expansion/pull/8974)
- `CMD_ARGS` for battle scripts now only exist in `src/battle_script_commands.c`
* Pret merge (20th of January, 2026) by @hedara90 in [#8973](https://github.com/rh-hideout/pokeemerald-expansion/pull/8973)
* Remove trailing whitespace - Master by @AsparagusEduardo in [#9011](https://github.com/rh-hideout/pokeemerald-expansion/pull/9011)
* fix: updated rulings about big feature label by @pkmnsnfrn in [#9027](https://github.com/rh-hideout/pokeemerald-expansion/pull/9027)
* Add aif2pcm to gitignore by @hedara90 in [#9077](https://github.com/rh-hideout/pokeemerald-expansion/pull/9077)
### Fixed
* Add check to warn of a non-working config setup by @FosterProgramming in [#8686](https://github.com/rh-hideout/pokeemerald-expansion/pull/8686)
* Various sprite visualizer fixes if configs disabled by @kittenchilly in [#8697](https://github.com/rh-hideout/pokeemerald-expansion/pull/8697)
* Fix trade evo with partner by @FosterProgramming in [#8857](https://github.com/rh-hideout/pokeemerald-expansion/pull/8857)
* Fixed Acc value shadow cut off when Accuracy = 100 by @montmoguri in [#8886](https://github.com/rh-hideout/pokeemerald-expansion/pull/8886)
* Fix vivillon icy snow icon by @FosterProgramming in [#8970](https://github.com/rh-hideout/pokeemerald-expansion/pull/8970)
* Fix premier ball wrong data size by @FosterProgramming in [#8979](https://github.com/rh-hideout/pokeemerald-expansion/pull/8979)
* Fixes creation of certain overworld sprites in object_event_pic_tables_followers.h by @ChrispyChris27 in [#9065](https://github.com/rh-hideout/pokeemerald-expansion/pull/9065)
## 🗺️ Overworld 🗺️
### Fixed
* Fix teleport location by @cawtds in [#8941](https://github.com/rh-hideout/pokeemerald-expansion/pull/8941)
* Fix substitute follower appearing with dead party by @FosterProgramming in [#9028](https://github.com/rh-hideout/pokeemerald-expansion/pull/9028)
* Fix berry tree spawning with max yield when OW_BERRY_ALWAYS_WATERABLE is active by @FosterProgramming in [#8976](https://github.com/rh-hideout/pokeemerald-expansion/pull/8976)
* Fix debug menu using female icon with male palette by @FosterProgramming in [#9092](https://github.com/rh-hideout/pokeemerald-expansion/pull/9092)
## 🐉 Pokémon 🐉
### Changed
* Miscellaneous species_info Changes by @amiosi in [#8462](https://github.com/rh-hideout/pokeemerald-expansion/pull/8462)
### Fixed
* Fix in-battle form changes always reverting by @AsparagusEduardo in [#8810](https://github.com/rh-hideout/pokeemerald-expansion/pull/8810)
* Fix typo in Salazzle form species ID table reference by @ostomachion in [#8904](https://github.com/rh-hideout/pokeemerald-expansion/pull/8904)
* Mega Gardevoir should always be Fairy-type by @amiosi in [#8955](https://github.com/rh-hideout/pokeemerald-expansion/pull/8955)
## ⚔️ Battle General ⚔️
### Changed
* Add enum for battle script commands by @AlexOn1ine in [#8778](https://github.com/rh-hideout/pokeemerald-expansion/pull/8778)
* Miscellaneous fixes to configs and other values by @amiosi in [#8662](https://github.com/rh-hideout/pokeemerald-expansion/pull/8662)
* Updating IsNonVolatileStatusBlocked by @bassforte123 in [#8728](https://github.com/rh-hideout/pokeemerald-expansion/pull/8728)
### Fixed
* Fix berry activation timing for Yawn sleep and Leech Seed damage by @moostoet in [#8776](https://github.com/rh-hideout/pokeemerald-expansion/pull/8776)
- Fix Chesto/Sitrus berry activation timing for status and damage
* Fix Cheek Pouch not activating for Bug Bite, Pluck, and Fling berry effects by @Cle-bit in [#8782](https://github.com/rh-hideout/pokeemerald-expansion/pull/8782)
* Fix wrongly getting a battler position in the type effectiveness functions by @Bassoonian in [#8787](https://github.com/rh-hideout/pokeemerald-expansion/pull/8787)
* fix crash damage implementation and incorrect memento generation by @amiosi in [#8804](https://github.com/rh-hideout/pokeemerald-expansion/pull/8804)
* Fix Sticky Hold blocking user's own Trick or Bestow by @Cle-bit in [#8860](https://github.com/rh-hideout/pokeemerald-expansion/pull/8860)
* Fixes Nightmare not affecting Comatose and adds various missing tests by @Cle-bit in [#8859](https://github.com/rh-hideout/pokeemerald-expansion/pull/8859)
* Fix Protosynthesis/Quark Drive defensive boost calculation by @hedara90 in [#8875](https://github.com/rh-hideout/pokeemerald-expansion/pull/8875)
* Fix wrong cases of DamageContext by @Bassoonian in [#8895](https://github.com/rh-hideout/pokeemerald-expansion/pull/8895)
* Fix misaligned shadows of transformed mons when `B_ENEMY_MON_SHADOW_STYLE <= GEN_3` by @estellarc in [#8887](https://github.com/rh-hideout/pokeemerald-expansion/pull/8887)
* fix ITEM_NONE being considered a form change item by DoesSpeciesUseHoldItemToChangeForm by @phexmiau in [#8915](https://github.com/rh-hideout/pokeemerald-expansion/pull/8915)
* Fix Memento and Block regressions by @amiosi in [#8942](https://github.com/rh-hideout/pokeemerald-expansion/pull/8942)
* Fixed several issues with Parting Shot by @Cle-bit in [#8928](https://github.com/rh-hideout/pokeemerald-expansion/pull/8928)
* Align Crafty Shield with wiki and refine IsAllyProtectingFromMove by @Cle-bit in [#8990](https://github.com/rh-hideout/pokeemerald-expansion/pull/8990)
* Fixes Hyperspace Fury not breaking protection by @PhallenTree in [#8999](https://github.com/rh-hideout/pokeemerald-expansion/pull/8999)
* Fix Magnetic Flux target handling in singles by @Cle-bit in [#9007](https://github.com/rh-hideout/pokeemerald-expansion/pull/9007)
* fix: IsDoubleBattle() return value by @khbsd in [#9012](https://github.com/rh-hideout/pokeemerald-expansion/pull/9012)
* Remove player party shiny bit setting in CreateFrontierBrainPokemon by @grintoul1 in [#9022](https://github.com/rh-hideout/pokeemerald-expansion/pull/9022)
* Fix Foresight/Miracle Eye repeated-use behavior by @Cle-bit in [#9025](https://github.com/rh-hideout/pokeemerald-expansion/pull/9025)
* Fix Crafty Shield consecutive-use failure by @Cle-bit in [#9023](https://github.com/rh-hideout/pokeemerald-expansion/pull/9023)
* Fixes Beak Blast burning attacker when charging 2 turn move by @PhallenTree in [#9026](https://github.com/rh-hideout/pokeemerald-expansion/pull/9026)
* Fix Synchronoise typeless behavior in Gen7+ by @Cle-bit in [#9031](https://github.com/rh-hideout/pokeemerald-expansion/pull/9031)
* Fix Psych Up wrong battler message and Gen 6+ crit ratio copying by @Cle-bit in [#9015](https://github.com/rh-hideout/pokeemerald-expansion/pull/9015)
* Add accuracy check to BattleScript_EffectNightmare by @AlexOn1ine in [#9032](https://github.com/rh-hideout/pokeemerald-expansion/pull/9032)
* Fixes to Commander and Emergency Exit by @AlexOn1ine in [#9040](https://github.com/rh-hideout/pokeemerald-expansion/pull/9040)
* Fixes Fling being usable with reusable TMs by @PhallenTree in [#8906](https://github.com/rh-hideout/pokeemerald-expansion/pull/8906)
* Fix Forewarn edge cases and random selection by @Cle-bit in [#9049](https://github.com/rh-hideout/pokeemerald-expansion/pull/9049)
* Fix Pickpocket moveend target checks and Thief/Covet handoff by @Cle-bit in [#9037](https://github.com/rh-hideout/pokeemerald-expansion/pull/9037)
* Fixes Infiltrator and adds config for Substitute interaction by @PhallenTree in [#9073](https://github.com/rh-hideout/pokeemerald-expansion/pull/9073)
* Fix Tranformed mon changing forms when fainting by @AsparagusEduardo in [#9106](https://github.com/rh-hideout/pokeemerald-expansion/pull/9106)
* Prevent Incinerate from burning items under Sticky Hold by @Cle-Bit in [#9068](https://github.com/rh-hideout/pokeemerald-expansion/pull/9068)
## 🤹 Moves 🤹
### Changed
* Corrected Stone Axe and Ceaseless Edge descriptions by @fdeblasio in [#9062](https://github.com/rh-hideout/pokeemerald-expansion/pull/9062)
### Fixed
* Fix Hyper Beam animation by @hedara90 in [#8872](https://github.com/rh-hideout/pokeemerald-expansion/pull/8872)
* Fixed instances of COMBO_STARTER_CHARGE used incorrectly by @fdeblasio in [#9034](https://github.com/rh-hideout/pokeemerald-expansion/pull/9034)
## 🧶 Items 🧶
### Changed
* Miscellaneous Item Changes by @amiosi in [#8461](https://github.com/rh-hideout/pokeemerald-expansion/pull/8461)
* add the type boost value for gen 3 sea incense by @amiosi in [#8826](https://github.com/rh-hideout/pokeemerald-expansion/pull/8826)
* Changes to Item icons and palettes by @amiosi in [#8614](https://github.com/rh-hideout/pokeemerald-expansion/pull/8614)
## 🤖 Battle AI 🤖
### Fixed
* Fix Sticky Hold blocking user's own Trick or Bestow by @Cle-bit in [#8860](https://github.com/rh-hideout/pokeemerald-expansion/pull/8860)
* Fix AI absorber switching for edge cases by @Cle-bit in [#8964](https://github.com/rh-hideout/pokeemerald-expansion/pull/8964)
* Fix the speed scoring of Tailwind for AI by @Cle-bit in [#8968](https://github.com/rh-hideout/pokeemerald-expansion/pull/8968)
* Fix AI wakeup-turn detection to consider Early Bird by @Cle-bit in [#9053](https://github.com/rh-hideout/pokeemerald-expansion/pull/9053)
## 🧹 Other Cleanup 🧹
* Misc style and whitespace cleanup by @grintoul1 in [#8681](https://github.com/rh-hideout/pokeemerald-expansion/pull/8681)
* Disable L button config (throw ball shortcut or move description) when there is overlap with L=A option by @FosterProgramming in [#8332](https://github.com/rh-hideout/pokeemerald-expansion/pull/8332)
* Various sprite visualizer fixes if configs disabled by @kittenchilly in [#8697](https://github.com/rh-hideout/pokeemerald-expansion/pull/8697)
* Updating IsNonVolatileStatusBlocked by @bassforte123 in [#8728](https://github.com/rh-hideout/pokeemerald-expansion/pull/8728)
* Deleted unnecessary files by @Bassoonian in [#8899](https://github.com/rh-hideout/pokeemerald-expansion/pull/8899)
* Fix Metronome bans by @amiosi in [#8834](https://github.com/rh-hideout/pokeemerald-expansion/pull/8834)
* Move CMD_ARGS to battle_script_commands by @hedara90 in [#8974](https://github.com/rh-hideout/pokeemerald-expansion/pull/8974)
- `CMD_ARGS` for battle scripts now only exist in `src/battle_script_commands.c`
* Remove trailing whitespace - Master by @AsparagusEduardo in [#9011](https://github.com/rh-hideout/pokeemerald-expansion/pull/9011)
* Corrected Stone Axe and Ceaseless Edge descriptions by @fdeblasio in [#9062](https://github.com/rh-hideout/pokeemerald-expansion/pull/9062)
* Add aif2pcm to gitignore by @hedara90 in [#9077](https://github.com/rh-hideout/pokeemerald-expansion/pull/9077)
* Fixes Infiltrator test battler not using intended move by @PhallenTree in [#9096](https://github.com/rh-hideout/pokeemerald-expansion/pull/9096)
## 🧪 Test Runner 🧪
### Changed
* Add inverse battle type matchup test by @izrofid in [#8779](https://github.com/rh-hideout/pokeemerald-expansion/pull/8779)
* `B_ABILITY_TRIGGER_CHANCE` config tests by @AsparagusEduardo in [#8594](https://github.com/rh-hideout/pokeemerald-expansion/pull/8594)
* Support end-of-battle party data check in tests by @AsparagusEduardo in [#8831](https://github.com/rh-hideout/pokeemerald-expansion/pull/8831)
- If you added tests that checks for party data (`gPlayerParty`), make sure that you're not using a species which changes form at the end of the battle, as its data could be overriten by the form change.
* Only test if move name fits on the bag screen for moves names within a TM/HM by @estellarc in [#8882](https://github.com/rh-hideout/pokeemerald-expansion/pull/8882)
* Added tests for fainting form changes by @AsparagusEduardo in [#8912](https://github.com/rh-hideout/pokeemerald-expansion/pull/8912)
* Add tests for type-changing abilities by @Cle-bit in [#8794](https://github.com/rh-hideout/pokeemerald-expansion/pull/8794)
* Fixes Infiltrator test battler not using intended move by @PhallenTree in [#9096](https://github.com/rh-hideout/pokeemerald-expansion/pull/9096)
### Fixed
* Fix Sticky Hold blocking user's own Trick or Bestow by @Cle-bit in [#8860](https://github.com/rh-hideout/pokeemerald-expansion/pull/8860)
* Fixes Nightmare not affecting Comatose and adds various missing tests by @Cle-bit in [#8859](https://github.com/rh-hideout/pokeemerald-expansion/pull/8859)
* Fixes Hyperspace Fury not breaking protection by @PhallenTree in [#8999](https://github.com/rh-hideout/pokeemerald-expansion/pull/8999)
* Fix Magnetic Flux target handling in singles by @Cle-bit in [#9007](https://github.com/rh-hideout/pokeemerald-expansion/pull/9007)
* Fix Foresight/Miracle Eye repeated-use behavior by @Cle-bit in [#9025](https://github.com/rh-hideout/pokeemerald-expansion/pull/9025)
* Fixes Beak Blast burning attacker when charging 2 turn move by @PhallenTree in [#9026](https://github.com/rh-hideout/pokeemerald-expansion/pull/9026)
* Fix Psych Up wrong battler message and Gen 6+ crit ratio copying by @Cle-bit in [#9015](https://github.com/rh-hideout/pokeemerald-expansion/pull/9015)
* Fix Pickpocket moveend target checks and Thief/Covet handoff by @Cle-bit in [#9037](https://github.com/rh-hideout/pokeemerald-expansion/pull/9037)
## 📚 Documentation 📚
* Add enum for battle script commands by @AlexOn1ine in [#8778](https://github.com/rh-hideout/pokeemerald-expansion/pull/8778)
* Port old list of credits to modern system by @Bassoonian in [#7887](https://github.com/rh-hideout/pokeemerald-expansion/pull/7887)
* Miscellaneous fixes to configs and other values by @amiosi in [#8662](https://github.com/rh-hideout/pokeemerald-expansion/pull/8662)
* Remove credits from code by @Bassoonian in [#8748](https://github.com/rh-hideout/pokeemerald-expansion/pull/8748)
* Miscellaneous species_info Changes by @amiosi in [#8462](https://github.com/rh-hideout/pokeemerald-expansion/pull/8462)
* Update CONTRIBUTING.md by @pkmnsnfrn in [#8879](https://github.com/rh-hideout/pokeemerald-expansion/pull/8879)
* Amend "SS Item" category of scope doc by @Pawkkie in [#8966](https://github.com/rh-hideout/pokeemerald-expansion/pull/8966)
* fix: updated rulings about big feature label by @pkmnsnfrn in [#9027](https://github.com/rh-hideout/pokeemerald-expansion/pull/9027)
## 👻 Sprites 👻
### Changed
* Changes to Item icons and palettes by @amiosi in [#8614](https://github.com/rh-hideout/pokeemerald-expansion/pull/8614)
### Fixed
* Fix vivillon icy snow icon by @FosterProgramming in [#8970](https://github.com/rh-hideout/pokeemerald-expansion/pull/8970)
* Fix premier ball wrong data size by @FosterProgramming in [#8979](https://github.com/rh-hideout/pokeemerald-expansion/pull/8979)
* Fixes creation of certain overworld sprites in object_event_pic_tables_followers.h by @ChrispyChris27 in [#9065](https://github.com/rh-hideout/pokeemerald-expansion/pull/9065)
## New Contributors
* @ostomachion made their first contribution in [#8904](https://github.com/rh-hideout/pokeemerald-expansion/pull/8904)
* @ChrispyChris27 made their first contribution in [#9065](https://github.com/rh-hideout/pokeemerald-expansion/pull/9065)
**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.14.2...expansion/1.14.3
<!--Last PR: 9099-->
<!--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,18 @@
#ifndef GUARD_BATTLE_ANIM_INTERNAL_H
#define GUARD_BATTLE_ANIM_INTERNAL_H
/* CMD_ARGS provides a way to locally name the members of gBattleAnimArgs.
*
* For example:
* {
* CMD_ARGS(x, y);
* // cmd->x is gBattleAnimArgs[0] and cmd->y is gBattleAnimArgs[1]
* } */
#if MODERN
#define CMD_ARGS(...) struct { s16 __VA_ARGS__; } *cmd = (void *)gBattleAnimArgs
#else
#define CMD_ARGS(...) struct CMD_ARGS { s16 __VA_ARGS__; }
#define cmd ((struct CMD_ARGS *)gBattleAnimArgs)
#endif
#endif

View File

@ -383,6 +383,7 @@ bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef);
bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef);
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum MoveEffect secondaryMoveEffect, enum FunctionCallOption option);
bool32 CanBeConfused(u32 battler);
bool32 IsSafeguardProtected(u32 battlerAtk, u32 battlerDef, u32 abilityAtk);
u32 GetBattlerAffectionHearts(u32 battler);
void TryToRevertMimicryAndFlags(void);
bool32 BattleArenaTurnEnd(void);

View File

@ -90,6 +90,7 @@
#define B_MINIMIZE_EVASION GEN_LATEST // In Gen5+, Minimize raises evasion by 2 stages instead of 1.
#define B_GROWTH_STAT_RAISE GEN_LATEST // In Gen5+, Growth raises Attack in addition to Special Attack by 1 stage each. Under the effects of the sun, it raises them by 2 stages each instead.
#define B_FOCUS_ENERGY_CRIT_RATIO GEN_LATEST // In Gen3+, Focus Energy increases critical hit ratio by 2 instead of 1.
#define B_PSYCH_UP_CRIT_RATIO GEN_LATEST // In Gen6+, Psych Up also copies the target's critical hit ratio.
// Other move settings
#define B_INCINERATE_GEMS GEN_LATEST // In Gen6+, Incinerate can destroy Gems.
@ -171,6 +172,7 @@
#define B_ATE_MULTIPLIER GEN_LATEST // In Gen7+, -ate abilities (Aerilate, Galvanize, Normalize, Pixilate, Refrigerate) multiply damage by 1.2. Otherwise, it's 1.3, except Normalize which has no multiplier.
#define B_DEFIANT_STICKY_WEB GEN_LATEST // In Gen9+, Defiant activates on Sticky Web regardless of who set it up. In Gen8, Defiant does not activate on Sticky Web set up by an ally after Court Change swaps its side.
#define B_POWDER_OVERCOAT GEN_LATEST // In Gen6+, Overcoat blocks powder and spore moves from affecting the user.
#define B_INFILTRATOR_SUBSTITUTE GEN_LATEST // In Gen6+, Infiltrator bypasses Substitute when using a move, excluding Transform and Sky Drop.
// Item settings
#define B_CONFUSE_BERRIES_HEAL GEN_LATEST // In Gens3-6, Figy and similar berries restore 1/8th of HP and trigger at half HP. In Gen7 they restore half HP, triggering at 25% HP. In Gen8 they heal 1/3rd of HP.

View File

@ -697,4 +697,7 @@ enum SpeciesGfxChange
// It's redundant with F_PAL_BATTLERS, because they're only ever used together to refer to all the battlers at once.
#define F_PAL_BATTLERS_2 (1 << 7 | 1 << 8 | 1 << 9 | 1 << 10)
enum { SHAKE_BG_X, SHAKE_BG_Y, SHAKE_MON_X, SHAKE_MON_Y };
enum { SHAKE_MON_ATTACKER, SHAKE_MON_TARGET, SHAKE_MON_BOTH };
#endif // GUARD_CONSTANTS_BATTLE_ANIM_H

View File

@ -1,10 +1,10 @@
#ifndef GUARD_CONSTANTS_EXPANSION_H
#define GUARD_CONSTANTS_EXPANSION_H
// Last version: 1.14.2
// Last version: 1.14.3
#define EXPANSION_VERSION_MAJOR 1
#define EXPANSION_VERSION_MINOR 14
#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.

View File

@ -4,200 +4,202 @@
/* Config definitions */
#define CONFIG_DEFINITIONS(F) \
/* Calculation settings */ \
F(CRIT_CHANCE, critChance, (u32, GEN_COUNT - 1)) \
F(CRIT_MULTIPLIER, critMultiplier, (u32, GEN_COUNT - 1)) \
F(PARALYSIS_SPEED, paralysisSpeed, (u32, GEN_COUNT - 1)) \
F(CONFUSION_SELF_DMG_CHANCE, confusionSelfDmgChance, (u32, GEN_COUNT - 1)) \
F(MULTI_HIT_CHANCE, multiHitChance, (u32, GEN_COUNT - 1)) \
F(WHITEOUT_MONEY, whiteoutMoney, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(LIGHT_BALL_ATTACK_BOOST, lightBallAttackBoost, (u32, GEN_COUNT - 1)) \
F(B_CRIT_CHANCE, critChance, (u32, GEN_COUNT - 1)) \
F(B_CRIT_MULTIPLIER, critMultiplier, (u32, GEN_COUNT - 1)) \
F(B_PARALYSIS_SPEED, paralysisSpeed, (u32, GEN_COUNT - 1)) \
F(B_CONFUSION_SELF_DMG_CHANCE, confusionSelfDmgChance, (u32, GEN_COUNT - 1)) \
F(B_MULTI_HIT_CHANCE, multiHitChance, (u32, GEN_COUNT - 1)) \
F(B_WHITEOUT_MONEY, whiteoutMoney, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_LIGHT_BALL_ATTACK_BOOST, lightBallAttackBoost, (u32, GEN_COUNT - 1)) \
/* Experience settings */ \
F(EXP_CATCH, expCatch, (u32, GEN_COUNT - 1)) \
F(TRAINER_EXP_MULTIPLIER, trainerExpMultiplier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SPLIT_EXP, splitExp, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SCALED_EXP, scaledExp, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(UNEVOLVED_EXP_MULTIPLIER, unevolvedExpMultiplier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(LEVEL_UP_NOTIFICATION, levelUpNotification, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_EXP_CATCH, expCatch, (u32, GEN_COUNT - 1)) \
F(B_TRAINER_EXP_MULTIPLIER, trainerExpMultiplier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SPLIT_EXP, splitExp, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SCALED_EXP, scaledExp, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_UNEVOLVED_EXP_MULTIPLIER, unevolvedExpMultiplier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_LEVEL_UP_NOTIFICATION, levelUpNotification, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Stat settings */ \
F(BADGE_BOOST, badgeBoost, (u32, GEN_COUNT - 1)) \
F(FRIENDSHIP_BOOST, friendshipBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(MAX_LEVEL_EV_GAINS, maxLevelEvGains, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(RECALCULATE_STATS, recalculateStats, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_BADGE_BOOST, badgeBoost, (u32, GEN_COUNT - 1)) \
F(B_FRIENDSHIP_BOOST, friendshipBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_MAX_LEVEL_EV_GAINS, maxLevelEvGains, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_RECALCULATE_STATS, recalculateStats, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Damage settings */ \
F(BURN_DAMAGE, burnDamage, (u32, GEN_COUNT - 1)) \
F(BURN_FACADE_DMG, burnFacadeDmg, (u32, GEN_COUNT - 1)) \
F(BINDING_DAMAGE, bindingDamage, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(PSYWAVE_DMG, psywaveDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(PAYBACK_SWITCH_BOOST, paybackSwitchBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(HIDDEN_POWER_DMG, hiddenPowerDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(ROUGH_SKIN_DMG, roughSkinDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(KNOCK_OFF_DMG, knockOffDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SPORT_DMG_REDUCTION, sportDmgReduction, (u32, GEN_COUNT - 1)) \
F(EXPLOSION_DEFENSE, explosionDefense, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(PARENTAL_BOND_DMG, parentalBondDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(MULTIPLE_TARGETS_DMG, multipleTargetsDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_BURN_DAMAGE, burnDamage, (u32, GEN_COUNT - 1)) \
F(B_BURN_FACADE_DMG, burnFacadeDmg, (u32, GEN_COUNT - 1)) \
F(B_BINDING_DAMAGE, bindingDamage, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_PSYWAVE_DMG, psywaveDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_PAYBACK_SWITCH_BOOST, paybackSwitchBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_HIDDEN_POWER_DMG, hiddenPowerDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_ROUGH_SKIN_DMG, roughSkinDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_KNOCK_OFF_DMG, knockOffDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SPORT_DMG_REDUCTION, sportDmgReduction, (u32, GEN_COUNT - 1)) \
F(B_EXPLOSION_DEFENSE, explosionDefense, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_PARENTAL_BOND_DMG, parentalBondDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_MULTIPLE_TARGETS_DMG, multipleTargetsDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Type settings */ \
F(GHOSTS_ESCAPE, ghostsEscape, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(PARALYZE_ELECTRIC, paralyzeElectric, (u32, GEN_COUNT - 1)) \
F(POWDER_GRASS, powderGrass, (u32, GEN_COUNT - 1)) \
F(POWDER_OVERCOAT, powderOvercoat, (u32, GEN_COUNT - 1)) \
F(UPDATED_TYPE_MATCHUPS, updatedTypeMatchups, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(PRANKSTER_DARK_TYPES, pranksterDarkTypes, (u32, GEN_COUNT - 1)) \
F(SHEER_COLD_IMMUNITY, sheerColdImmunity, (u32, GEN_COUNT - 1)) \
F(ROOST_PURE_FLYING, roostPureFlying, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(STATUS_TYPE_IMMUNITY, statusTypeImmunity, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_GHOSTS_ESCAPE, ghostsEscape, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_PARALYZE_ELECTRIC, paralyzeElectric, (u32, GEN_COUNT - 1)) \
F(B_POWDER_GRASS, powderGrass, (u32, GEN_COUNT - 1)) \
F(B_POWDER_OVERCOAT, powderOvercoat, (u32, GEN_COUNT - 1)) \
F(B_UPDATED_TYPE_MATCHUPS, updatedTypeMatchups, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_PRANKSTER_DARK_TYPES, pranksterDarkTypes, (u32, GEN_COUNT - 1)) \
F(B_SHEER_COLD_IMMUNITY, sheerColdImmunity, (u32, GEN_COUNT - 1)) \
F(B_ROOST_PURE_FLYING, roostPureFlying, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_STATUS_TYPE_IMMUNITY, statusTypeImmunity, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Turn settings */ \
F(BINDING_TURNS, bindingTurns, (u32, GEN_COUNT - 1)) \
F(UPROAR_TURNS, uproarTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(UPROAR_IGNORE_SOUNDPROOF, uproarIgnoreSoundproof, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(DISABLE_TURNS, disableTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TAILWIND_TURNS, tailwindTurns, (u32, GEN_COUNT - 1)) \
F(SLEEP_TURNS, sleepTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TAUNT_TURNS, tauntTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SPORT_TURNS, sportTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(MEGA_EVO_TURN_ORDER, megaEvoTurnOrder, (u32, GEN_COUNT - 1)) \
F(RECALC_TURN_AFTER_ACTIONS, recalcTurnAfterActions, (u32, GEN_COUNT - 1)) \
F(FAINT_SWITCH_IN, faintSwitchIn, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_BINDING_TURNS, bindingTurns, (u32, GEN_COUNT - 1)) \
F(B_UPROAR_TURNS, uproarTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_UPROAR_IGNORE_SOUNDPROOF, uproarIgnoreSoundproof, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_DISABLE_TURNS, disableTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_TAILWIND_TURNS, tailwindTurns, (u32, GEN_COUNT - 1)) \
F(B_SLEEP_TURNS, sleepTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_TAUNT_TURNS, tauntTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SPORT_TURNS, sportTurns, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_MEGA_EVO_TURN_ORDER, megaEvoTurnOrder, (u32, GEN_COUNT - 1)) \
F(B_RECALC_TURN_AFTER_ACTIONS, recalcTurnAfterActions, (u32, GEN_COUNT - 1)) \
F(B_FAINT_SWITCH_IN, faintSwitchIn, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Move data settings */ \
F(UPDATED_MOVE_DATA, updatedMoveData, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(UPDATED_MOVE_TYPES, updatedMoveTypes, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(UPDATED_MOVE_FLAGS, updatedMoveFlags, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(PHYSICAL_SPECIAL_SPLIT, physicalSpecialSplit, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(RECOIL_IF_MISS_DMG, recoilIfMissDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(KLUTZ_FLING_INTERACTION, klutzFlingInteraction, (u32, GEN_COUNT - 1)) \
F(UPDATED_CONVERSION, updatedConversion, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(UPDATED_CONVERSION_2, updatedConversion2, (u32, GEN_COUNT - 1)) \
F(PP_REDUCED_BY_SPITE, ppReducedBySpite, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(EXTRAPOLATED_MOVE_FLAGS, extrapolatedMoveFlags, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_UPDATED_MOVE_DATA, updatedMoveData, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_UPDATED_MOVE_TYPES, updatedMoveTypes, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_UPDATED_MOVE_FLAGS, updatedMoveFlags, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_PHYSICAL_SPECIAL_SPLIT, physicalSpecialSplit, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_RECOIL_IF_MISS_DMG, recoilIfMissDmg, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_KLUTZ_FLING_INTERACTION, klutzFlingInteraction, (u32, GEN_COUNT - 1)) \
F(B_UPDATED_CONVERSION, updatedConversion, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_UPDATED_CONVERSION_2, updatedConversion2, (u32, GEN_COUNT - 1)) \
F(B_PP_REDUCED_BY_SPITE, ppReducedBySpite, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_EXTRAPOLATED_MOVE_FLAGS, extrapolatedMoveFlags, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Ability data settings */ \
F(UPDATED_ABILITY_DATA, updatedAbilityData, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_UPDATED_ABILITY_DATA, updatedAbilityData, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Move accuracy settings */ \
F(TOXIC_NEVER_MISS, toxicNeverMiss, (u32, GEN_COUNT - 1)) \
F(MINIMIZE_DMG_ACC, minimizeDmgAcc, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(BLIZZARD_HAIL, blizzardHail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SHEER_COLD_ACC, sheerColdAcc, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_TOXIC_NEVER_MISS, toxicNeverMiss, (u32, GEN_COUNT - 1)) \
F(B_MINIMIZE_DMG_ACC, minimizeDmgAcc, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_BLIZZARD_HAIL, blizzardHail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SHEER_COLD_ACC, sheerColdAcc, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Move stat change settings */ \
F(FELL_STINGER_STAT_RAISE, fellStingerStatRaise, (u32, GEN_COUNT - 1)) \
F(KINGS_SHIELD_LOWER_ATK, kingsShieldLowerAtk, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SPEED_BUFFING_RAPID_SPIN, speedBuffingRapidSpin, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(CHARGE_SPDEF_RAISE, chargeSpDefRaise, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(MINIMIZE_EVASION, minimizeEvasion, (u32, GEN_COUNT - 1)) \
F(GROWTH_STAT_RAISE, growthStatRaise, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(FOCUS_ENERGY_CRIT_RATIO, focusEnergyCritRatio, (u32, GEN_COUNT - 1)) \
F(B_FELL_STINGER_STAT_RAISE, fellStingerStatRaise, (u32, GEN_COUNT - 1)) \
F(B_KINGS_SHIELD_LOWER_ATK, kingsShieldLowerAtk, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SPEED_BUFFING_RAPID_SPIN, speedBuffingRapidSpin, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_CHARGE_SPDEF_RAISE, chargeSpDefRaise, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_MINIMIZE_EVASION, minimizeEvasion, (u32, GEN_COUNT - 1)) \
F(B_GROWTH_STAT_RAISE, growthStatRaise, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_FOCUS_ENERGY_CRIT_RATIO, focusEnergyCritRatio, (u32, GEN_COUNT - 1)) \
F(B_PSYCH_UP_CRIT_RATIO, psychUpCritRatio, (u32, GEN_COUNT - 1)) \
/* Other move settings */ \
F(INCINERATE_GEMS, incinerateGems, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(CAN_SPITE_FAIL, canSpiteFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(CRASH_IF_TARGET_IMMUNE, crashIfTargetImmune, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(MEMENTO_FAIL, mementoFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(PARTING_SHOT_SWITCH, partingShotSwitch, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(GLARE_GHOST, glareGhost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SKILL_SWAP, skillSwap, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(BRICK_BREAK, brickBreak, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(WISH_HP_SOURCE, wishHpSource, (u32, GEN_COUNT - 1)) \
F(RAMPAGE_CANCELLING, rampageCancelling, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(HEAL_BLOCKING, healBlocking, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(ROOTED_GROUNDING, rootedGrounding, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(METRONOME_MOVES, metronomeMoves, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TELEPORT_BEHAVIOR, teleportBehavior, (u32, GEN_COUNT - 1)) \
F(BEAT_UP, beatUp, (u32, GEN_COUNT - 1)) \
F(DARK_VOID_FAIL, darkVoidFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(BURN_HIT_THAW, burnHitThaw, (u32, GEN_COUNT - 1)) \
F(HEALING_WISH_SWITCH, healingWishSwitch, (u32, GEN_COUNT - 1)) \
F(DEFOG_EFFECT_CLEARING, defogEffectClearing, (u32, GEN_COUNT - 1)) \
F(STOCKPILE_RAISES_DEFS, stockpileRaisesDefs, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TRANSFORM_SHINY, transformShiny, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TRANSFORM_FORM_CHANGES, transformFormChanges, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(WIDE_GUARD, wideGuard, (u32, GEN_COUNT - 1)) \
F(QUICK_GUARD, quickGuard, (u32, GEN_COUNT - 1)) \
F(IMPRISON, imprison, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(ALLY_SWITCH_FAIL_CHANCE, allySwitchFailChance, (u32, GEN_COUNT - 1)) \
F(SKETCH_BANS, sketchBans, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(KNOCK_OFF_REMOVAL, knockOffRemoval, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(HEAL_BELL_SOUNDPROOF, healBellSoundproof, (u32, GEN_COUNT - 1)) \
F(CHARGE, charge, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(POWDER_RAIN, powderRain, (u32, GEN_COUNT - 1)) \
F(AFTER_YOU_TURN_ORDER, afterYouTurnOrder, (u32, GEN_COUNT - 1)) \
F(QUASH_TURN_ORDER, quashTurnOrder, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(DESTINY_BOND_FAIL, destinyBondFail, (u32, GEN_COUNT - 1)) \
F(FORESIGHT_FAIL, foresightFail, (u32, GEN_COUNT - 1)) \
F(MIRACLE_EYE_FAIL, miracleEyeFail, (u32, GEN_COUNT - 1)) \
F(PURSUIT_TARGET, pursuitTarget, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SKIP_RECHARGE, skipRecharge, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(ENCORE_TARGET, encoreTarget, (u32, GEN_COUNT - 1)) \
F(TIME_OF_DAY_HEALING_MOVES, timeOfDayHealingMoves, (u32, GEN_COUNT - 1)) \
F(DREAM_EATER_LIQUID_OOZE, dreamEaterLiquidOoze, (u32, GEN_COUNT - 1)) \
F(B_INCINERATE_GEMS, incinerateGems, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_CAN_SPITE_FAIL, canSpiteFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_CRASH_IF_TARGET_IMMUNE, crashIfTargetImmune, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_MEMENTO_FAIL, mementoFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_PARTING_SHOT_SWITCH, partingShotSwitch, (u32, GEN_COUNT - 1)) \
F(B_GLARE_GHOST, glareGhost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SKILL_SWAP, skillSwap, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_BRICK_BREAK, brickBreak, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_WISH_HP_SOURCE, wishHpSource, (u32, GEN_COUNT - 1)) \
F(B_RAMPAGE_CANCELLING, rampageCancelling, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_HEAL_BLOCKING, healBlocking, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_ROOTED_GROUNDING, rootedGrounding, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_METRONOME_MOVES, metronomeMoves, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_TELEPORT_BEHAVIOR, teleportBehavior, (u32, GEN_COUNT - 1)) \
F(B_BEAT_UP, beatUp, (u32, GEN_COUNT - 1)) \
F(B_DARK_VOID_FAIL, darkVoidFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_BURN_HIT_THAW, burnHitThaw, (u32, GEN_COUNT - 1)) \
F(B_HEALING_WISH_SWITCH, healingWishSwitch, (u32, GEN_COUNT - 1)) \
F(B_DEFOG_EFFECT_CLEARING, defogEffectClearing, (u32, GEN_COUNT - 1)) \
F(B_STOCKPILE_RAISES_DEFS, stockpileRaisesDefs, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_TRANSFORM_SHINY, transformShiny, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_TRANSFORM_FORM_CHANGES, transformFormChanges, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_WIDE_GUARD, wideGuard, (u32, GEN_COUNT - 1)) \
F(B_QUICK_GUARD, quickGuard, (u32, GEN_COUNT - 1)) \
F(B_IMPRISON, imprison, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_ALLY_SWITCH_FAIL_CHANCE, allySwitchFailChance, (u32, GEN_COUNT - 1)) \
F(B_SKETCH_BANS, sketchBans, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_KNOCK_OFF_REMOVAL, knockOffRemoval, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_HEAL_BELL_SOUNDPROOF, healBellSoundproof, (u32, GEN_COUNT - 1)) \
F(B_CHARGE, charge, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_POWDER_RAIN, powderRain, (u32, GEN_COUNT - 1)) \
F(B_AFTER_YOU_TURN_ORDER, afterYouTurnOrder, (u32, GEN_COUNT - 1)) \
F(B_QUASH_TURN_ORDER, quashTurnOrder, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_DESTINY_BOND_FAIL, destinyBondFail, (u32, GEN_COUNT - 1)) \
F(B_FORESIGHT_FAIL, foresightFail, (u32, GEN_COUNT - 1)) \
F(B_MIRACLE_EYE_FAIL, miracleEyeFail, (u32, GEN_COUNT - 1)) \
F(B_PURSUIT_TARGET, pursuitTarget, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SKIP_RECHARGE, skipRecharge, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_ENCORE_TARGET, encoreTarget, (u32, GEN_COUNT - 1)) \
F(B_TIME_OF_DAY_HEALING_MOVES, timeOfDayHealingMoves, (u32, GEN_COUNT - 1)) \
F(B_DREAM_EATER_LIQUID_OOZE, dreamEaterLiquidOoze, (u32, GEN_COUNT - 1)) \
/* Ability settings */ \
F(GALE_WINGS, galeWings, (u32, GEN_COUNT - 1)) \
F(STANCE_CHANGE_FAIL, stanceChangeFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SHADOW_TAG_ESCAPE, shadowTagEscape, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(MOODY_ACC_EVASION, moodyAccEvasion, (u32, GEN_COUNT - 1)) \
F(FLASH_FIRE_FROZEN, flashFireFrozen, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SYNCHRONIZE_TOXIC, synchronizeToxic, (u32, GEN_COUNT - 1)) \
F(UPDATED_INTIMIDATE, updatedIntimidate, (u32, GEN_COUNT - 1)) \
F(OBLIVIOUS_TAUNT, obliviousTaunt, (u32, GEN_COUNT - 1)) \
F(STURDY, sturdy, (u32, GEN_COUNT - 1)) \
F(PLUS_MINUS_INTERACTION, plusMinusInteraction, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(WEATHER_FORMS, weatherForms, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SYMBIOSIS_GEMS, symbiosisGems, (u32, GEN_COUNT - 1)) \
F(ABSORBING_ABILITY_STRING, absorbingAbilityString, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(REDIRECT_ABILITY_IMMUNITY, redirectAbilityImmunity, (u32, GEN_COUNT - 1)) \
F(REDIRECT_ABILITY_ALLIES, redirectAbilityAllies, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(LEAF_GUARD_PREVENTS_REST, leafGuardPreventsRest, (u32, GEN_COUNT - 1)) \
F(TRANSISTOR_BOOST, transistorBoost, (u32, GEN_COUNT - 1)) \
F(ILLUMINATE_EFFECT, illuminateEffect, (u32, GEN_COUNT - 1)) \
F(WEAK_ARMOR_SPEED, weakArmorSpeed, (u32, GEN_COUNT - 1)) \
F(PROTEAN_LIBERO, proteanLibero, (u32, GEN_COUNT - 1)) \
F(INTREPID_SWORD, intrepidSword, (u32, GEN_COUNT - 1)) \
F(DAUNTLESS_SHIELD, dauntlessShield, (u32, GEN_COUNT - 1)) \
F(DISGUISE_HP_LOSS, disguiseHpLoss, (u32, GEN_COUNT - 1)) \
F(ABILITY_TRIGGER_CHANCE, abilityTriggerChance, (u32, GEN_COUNT - 1)) \
F(PICKUP_WILD, pickupWild, (u32, GEN_COUNT - 1)) \
F(MAGIC_GUARD, magicGuard, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(BATTLE_BOND, battleBond, (u32, GEN_COUNT - 1)) \
F(ATE_MULTIPLIER, ateMultiplier, (u32, GEN_COUNT - 1)) \
F(DEFIANT_STICKY_WEB, defiantStickyWeb, (u32, GEN_COUNT - 1)) \
F(B_GALE_WINGS, galeWings, (u32, GEN_COUNT - 1)) \
F(B_STANCE_CHANGE_FAIL, stanceChangeFail, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SHADOW_TAG_ESCAPE, shadowTagEscape, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_MOODY_ACC_EVASION, moodyAccEvasion, (u32, GEN_COUNT - 1)) \
F(B_FLASH_FIRE_FROZEN, flashFireFrozen, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SYNCHRONIZE_TOXIC, synchronizeToxic, (u32, GEN_COUNT - 1)) \
F(B_UPDATED_INTIMIDATE, updatedIntimidate, (u32, GEN_COUNT - 1)) \
F(B_OBLIVIOUS_TAUNT, obliviousTaunt, (u32, GEN_COUNT - 1)) \
F(B_STURDY, sturdy, (u32, GEN_COUNT - 1)) \
F(B_PLUS_MINUS_INTERACTION, plusMinusInteraction, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_WEATHER_FORMS, weatherForms, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SYMBIOSIS_GEMS, symbiosisGems, (u32, GEN_COUNT - 1)) \
F(B_ABSORBING_ABILITY_STRING, absorbingAbilityString, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_REDIRECT_ABILITY_IMMUNITY, redirectAbilityImmunity, (u32, GEN_COUNT - 1)) \
F(B_REDIRECT_ABILITY_ALLIES, redirectAbilityAllies, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_LEAF_GUARD_PREVENTS_REST, leafGuardPreventsRest, (u32, GEN_COUNT - 1)) \
F(B_TRANSISTOR_BOOST, transistorBoost, (u32, GEN_COUNT - 1)) \
F(B_ILLUMINATE_EFFECT, illuminateEffect, (u32, GEN_COUNT - 1)) \
F(B_WEAK_ARMOR_SPEED, weakArmorSpeed, (u32, GEN_COUNT - 1)) \
F(B_PROTEAN_LIBERO, proteanLibero, (u32, GEN_COUNT - 1)) \
F(B_INTREPID_SWORD, intrepidSword, (u32, GEN_COUNT - 1)) \
F(B_DAUNTLESS_SHIELD, dauntlessShield, (u32, GEN_COUNT - 1)) \
F(B_DISGUISE_HP_LOSS, disguiseHpLoss, (u32, GEN_COUNT - 1)) \
F(B_ABILITY_TRIGGER_CHANCE, abilityTriggerChance, (u32, GEN_COUNT - 1)) \
F(B_PICKUP_WILD, pickupWild, (u32, GEN_COUNT - 1)) \
F(B_MAGIC_GUARD, magicGuard, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_BATTLE_BOND, battleBond, (u32, GEN_COUNT - 1)) \
F(B_ATE_MULTIPLIER, ateMultiplier, (u32, GEN_COUNT - 1)) \
F(B_DEFIANT_STICKY_WEB, defiantStickyWeb, (u32, GEN_COUNT - 1)) \
F(B_INFILTRATOR_SUBSTITUTE, infiltratorSubstitute, (u32, GEN_COUNT - 1)) \
/* Item settings */ \
F(CONFUSE_BERRIES_HEAL, confuseBerriesHeal, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(X_ITEMS_BUFF, xItemsBuff, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(MENTAL_HERB, mentalHerb, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TRAINERS_KNOCK_OFF_ITEMS, trainersKnockOffItems, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(RETURN_STOLEN_NPC_ITEMS, returnStolenNpcItems, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(STEAL_WILD_ITEMS, stealWildItems, (u32, GEN_COUNT - 1)) \
F(RESTORE_HELD_BATTLE_ITEMS, restoreHeldBattleItems, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SOUL_DEW_BOOST, soulDewBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(NET_BALL_MODIFIER, netBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(DIVE_BALL_MODIFIER, diveBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(NEST_BALL_MODIFIER, nestBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(REPEAT_BALL_MODIFIER, repeatBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(TIMER_BALL_MODIFIER, timerBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(DUSK_BALL_MODIFIER, duskBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(QUICK_BALL_MODIFIER, quickBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(LURE_BALL_MODIFIER, lureBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(HEAVY_BALL_MODIFIER, heavyBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(DREAM_BALL_MODIFIER, dreamBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SPORT_BALL_MODIFIER, sportBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SAFARI_BALL_MODIFIER, safariBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(FRIEND_BALL_MODIFIER, friendBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SERENE_GRACE_BOOST, sereneGraceBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(IRON_BALL, ironBall, (u32, GEN_COUNT - 1)) \
F(B_CONFUSE_BERRIES_HEAL, confuseBerriesHeal, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_X_ITEMS_BUFF, xItemsBuff, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_MENTAL_HERB, mentalHerb, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_TRAINERS_KNOCK_OFF_ITEMS, trainersKnockOffItems, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_RETURN_STOLEN_NPC_ITEMS, returnStolenNpcItems, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_STEAL_WILD_ITEMS, stealWildItems, (u32, GEN_COUNT - 1)) \
F(B_RESTORE_HELD_BATTLE_ITEMS, restoreHeldBattleItems, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SOUL_DEW_BOOST, soulDewBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_NET_BALL_MODIFIER, netBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_DIVE_BALL_MODIFIER, diveBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_NEST_BALL_MODIFIER, nestBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_REPEAT_BALL_MODIFIER, repeatBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_TIMER_BALL_MODIFIER, timerBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_DUSK_BALL_MODIFIER, duskBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_QUICK_BALL_MODIFIER, quickBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_LURE_BALL_MODIFIER, lureBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_HEAVY_BALL_MODIFIER, heavyBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_DREAM_BALL_MODIFIER, dreamBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SPORT_BALL_MODIFIER, sportBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SAFARI_BALL_MODIFIER, safariBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_FRIEND_BALL_MODIFIER, friendBallModifier, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SERENE_GRACE_BOOST, sereneGraceBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_IRON_BALL, ironBall, (u32, GEN_COUNT - 1)) \
/* Weather settings */ \
F(ABILITY_WEATHER, abilityWeather, (u32, GEN_COUNT - 1)) \
F(SANDSTORM_SPDEF_BOOST, sandstormSpDefBoost, (u32, GEN_COUNT - 1)) \
F(OVERWORLD_FOG, overworldFog, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(OVERWORLD_SNOW, overworldSnow, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SNOW_WARNING, snowWarning, (u32, GEN_COUNT - 1)) \
F(PREFERRED_ICE_WEATHER, preferredIceWeather, (u32, B_ICE_WEATHER_SNOW)) /* TODO: use in tests */ \
F(B_ABILITY_WEATHER, abilityWeather, (u32, GEN_COUNT - 1)) \
F(B_SANDSTORM_SPDEF_BOOST, sandstormSpDefBoost, (u32, GEN_COUNT - 1)) \
F(B_OVERWORLD_FOG, overworldFog, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_OVERWORLD_SNOW, overworldSnow, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SNOW_WARNING, snowWarning, (u32, GEN_COUNT - 1)) \
F(B_PREFERRED_ICE_WEATHER, preferredIceWeather, (u32, B_ICE_WEATHER_SNOW)) /* TODO: use in tests */ \
/* Terrain settings */ \
F(TERRAIN_TYPE_BOOST, terrainTypeBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SECRET_POWER_EFFECT, secretPowerEffect, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(SECRET_POWER_ANIMATION, secretPowerAnimation, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(NATURE_POWER_MOVES, naturePowerMoves, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(CAMOUFLAGE_TYPES, camouflageTypes, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_TERRAIN_TYPE_BOOST, terrainTypeBoost, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SECRET_POWER_EFFECT, secretPowerEffect, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_SECRET_POWER_ANIMATION, secretPowerAnimation, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_NATURE_POWER_MOVES, naturePowerMoves, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_CAMOUFLAGE_TYPES, camouflageTypes, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
/* Other settings */ \
F(WILD_NATURAL_ENEMIES, wildNaturalEnemies, (u32, TRUE)) /* TODO: use in tests */ \
F(AFFECTION_MECHANICS, affectionMechanics, (u32, TRUE)) /* TODO: use in tests */ \
F(OBEDIENCE_MECHANICS, obedienceMechanics, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(USE_FROSTBITE, useFrostbite, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_WILD_NATURAL_ENEMIES, wildNaturalEnemies, (u32, TRUE)) /* TODO: use in tests */ \
F(B_AFFECTION_MECHANICS, affectionMechanics, (u32, TRUE)) /* TODO: use in tests */ \
F(B_OBEDIENCE_MECHANICS, obedienceMechanics, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
F(B_USE_FROSTBITE, useFrostbite, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
#define GET_CONFIG_MAXIMUM(_typeMaxValue, ...) INVOKE_WITH_B(GET_CONFIG_MAXIMUM_, _typeMaxValue)

View File

@ -16,7 +16,9 @@ struct GenChanges
// ...
};
u32 GetConfig(enum ConfigTag configTag);
#define GetConfig(name) GetConfigInternal(CONFIG_##name)
u32 GetConfigInternal(enum ConfigTag configTag);
void SetConfig(enum ConfigTag configTag, u32 value);
#if TESTING

View File

@ -167,6 +167,7 @@ enum RandomTag
RNG_QUICK_DRAW,
RNG_QUICK_CLAW,
RNG_TRACE,
RNG_FOREWARN,
RNG_FICKLE_BEAM,
RNG_AI_ABILITY,
RNG_AI_SWITCH_HASBADODDS,

View File

@ -309,7 +309,7 @@
* of `enum ConfigTag`
* Example:
* GIVEN {
* WITH_CONFIG(CONFIG_GALE_WINGS, GEN_6);
* WITH_CONFIG(B_GALE_WINGS, GEN_6);
* }
* The `value` may be inferred from a local variable, e.g. set by
* PARAMETRIZE.
@ -970,7 +970,7 @@ struct moveWithPP {
#define AI_LOG AILogScores(__LINE__)
#define FLAG_SET(flagId) SetFlagForTest(__LINE__, flagId)
#define WITH_CONFIG(configTag, value) TestSetConfig(__LINE__, configTag, value)
#define WITH_CONFIG(configTag, value) TestSetConfig(__LINE__, CONFIG_##configTag, value)
#define PLAYER(species) for (OpenPokemon(__LINE__, B_POSITION_PLAYER_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__))
#define OPPONENT(species) for (OpenPokemon(__LINE__, B_POSITION_OPPONENT_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__))

View File

@ -1267,7 +1267,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
} // def partner ability checks
// gen7+ dark type mons immune to priority->elevated moves from prankster
if (GetConfig(CONFIG_PRANKSTER_DARK_TYPES) >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)
if (GetConfig(B_PRANKSTER_DARK_TYPES) >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)
&& aiData->abilities[battlerAtk] == ABILITY_PRANKSTER && IsBattleMoveStatus(move)
&& !(moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER)))
RETURN_SCORE_MINUS(10);
@ -1729,7 +1729,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
break;
case EFFECT_SHEER_COLD:
if (GetConfig(CONFIG_SHEER_COLD_IMMUNITY) >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE))
if (GetConfig(B_SHEER_COLD_IMMUNITY) >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE))
RETURN_SCORE_MINUS(20);
// fallthrough
case EFFECT_OHKO:
@ -3396,7 +3396,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case ABILITY_VOLT_ABSORB:
if (moveType == TYPE_ELECTRIC)
{
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) < GEN_5 && atkPartnerAbility == ABILITY_LIGHTNING_ROD)
if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) < GEN_5 && atkPartnerAbility == ABILITY_LIGHTNING_ROD)
{
RETURN_SCORE_MINUS(10);
}
@ -3442,7 +3442,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case ABILITY_STORM_DRAIN:
if (moveType == TYPE_WATER)
{
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) < GEN_5 && atkPartnerAbility == ABILITY_STORM_DRAIN)
if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) < GEN_5 && atkPartnerAbility == ABILITY_STORM_DRAIN)
{
RETURN_SCORE_MINUS(10);
}
@ -5395,7 +5395,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
case EFFECT_ION_DELUGE:
if ((aiData->abilities[battlerAtk] == ABILITY_VOLT_ABSORB
|| aiData->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE
|| (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD))
|| (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD))
&& predictedType == TYPE_NORMAL)
ADJUST_SCORE(DECENT_EFFECT);
break;
@ -5455,7 +5455,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
if (predictedMove != MOVE_NONE
&& (aiData->abilities[battlerAtk] == ABILITY_VOLT_ABSORB
|| aiData->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE
|| (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD)))
|| (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD)))
{
ADJUST_SCORE(DECENT_EFFECT);
}

View File

@ -298,7 +298,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
// Check if mon gets one shot
if (maxDamageTaken > gBattleMons[battler].hp
&& !(gItemsInfo[gBattleMons[battler].item].holdEffect == HOLD_EFFECT_FOCUS_SASH || (!IsMoldBreakerTypeAbility(opposingBattler, gAiLogicData->abilities[opposingBattler]) && GetConfig(CONFIG_STURDY) >= GEN_5 && aiAbility == ABILITY_STURDY)))
&& !(gItemsInfo[gBattleMons[battler].item].holdEffect == HOLD_EFFECT_FOCUS_SASH || (!IsMoldBreakerTypeAbility(opposingBattler, gAiLogicData->abilities[opposingBattler]) && GetConfig(B_STURDY) >= GEN_5 && aiAbility == ABILITY_STURDY)))
{
getsOneShot = TRUE;
}
@ -534,14 +534,14 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
{
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_WATER_ABSORB;
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_DRY_SKIN;
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_STORM_DRAIN;
}
if (incomingType == TYPE_ELECTRIC || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_ELECTRIC))
{
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_VOLT_ABSORB;
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_MOTOR_DRIVE;
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_LIGHTNING_ROD;
}
if (incomingType == TYPE_GRASS || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_GRASS))
@ -567,7 +567,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
}
if (IsPowderMove(incomingMove) || (isOpposingBattlerChargingOrInvulnerable && IsPowderMove(incomingMove)))
{
if (GetConfig(CONFIG_POWDER_OVERCOAT) >= GEN_6)
if (GetConfig(B_POWDER_OVERCOAT) >= GEN_6)
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_OVERCOAT;
}
if (numAbsorbingAbilities == 0)
@ -720,7 +720,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
&& gAiLogicData->abilities[opposingBattler] != ABILITY_UNAWARE
&& gAiLogicData->abilities[opposingBattler] != ABILITY_KEEN_EYE
&& gAiLogicData->abilities[opposingBattler] != ABILITY_MINDS_EYE
&& (GetConfig(CONFIG_ILLUMINATE_EFFECT) >= GEN_9 && gAiLogicData->abilities[opposingBattler] != ABILITY_ILLUMINATE)
&& (GetConfig(B_ILLUMINATE_EFFECT) >= GEN_9 && gAiLogicData->abilities[opposingBattler] != ABILITY_ILLUMINATE)
&& !gBattleMons[battler].volatiles.foresight
&& !gBattleMons[battler].volatiles.miracleEye)
switchMon = FALSE;
@ -1763,7 +1763,7 @@ static u32 GetSwitchinStatusDamage(u32 battler)
{
if (status & STATUS1_BURN)
{
if (GetConfig(CONFIG_BURN_DAMAGE) >= GEN_7 || GetConfig(CONFIG_BURN_DAMAGE) == GEN_1)
if (GetConfig(B_BURN_DAMAGE) >= GEN_7 || GetConfig(B_BURN_DAMAGE) == GEN_1)
statusDamage = maxHP / 16;
else
statusDamage = maxHP / 8;
@ -1774,7 +1774,7 @@ static u32 GetSwitchinStatusDamage(u32 battler)
}
else if (status & STATUS1_FROSTBITE)
{
if (GetConfig(CONFIG_BURN_DAMAGE) >= GEN_7 || GetConfig(CONFIG_BURN_DAMAGE) == GEN_1)
if (GetConfig(B_BURN_DAMAGE) >= GEN_7 || GetConfig(B_BURN_DAMAGE) == GEN_1)
statusDamage = maxHP / 16;
else
statusDamage = maxHP / 8;
@ -1858,7 +1858,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler)
currentHP = currentHP - damageTaken;
// One shot prevention effects
if (damageTaken >= maxHP && startingHP == maxHP && (heldItemEffect == HOLD_EFFECT_FOCUS_SASH || (!opponentCanBreakMold && GetConfig(CONFIG_STURDY) >= GEN_5 && ability == ABILITY_STURDY)) && hitsToKO < 1)
if (damageTaken >= maxHP && startingHP == maxHP && (heldItemEffect == HOLD_EFFECT_FOCUS_SASH || (!opponentCanBreakMold && GetConfig(B_STURDY) >= GEN_5 && ability == ABILITY_STURDY)) && hitsToKO < 1)
currentHP = 1;
// If mon is still alive, apply weather impact first, as it might KO the mon before it can heal with its item (order is weather -> item -> status)
@ -2050,7 +2050,7 @@ static s32 GetMaxPriorityDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposi
static bool32 CanAbilityTrapOpponent(enum Ability ability, u32 opponent)
{
if ((GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(opponent, TYPE_GHOST)))
if ((GetConfig(B_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(opponent, TYPE_GHOST)))
return FALSE;
else if (ability == ABILITY_SHADOW_TAG)
{

View File

@ -474,7 +474,7 @@ bool32 AI_CanBattlerEscape(u32 battler)
{
enum HoldEffect holdEffect = gAiLogicData->holdEffects[battler];
if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
if (GetConfig(B_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
return TRUE;
if (holdEffect == HOLD_EFFECT_SHED_SHELL)
return TRUE;
@ -818,7 +818,7 @@ static inline void CalcDynamicMoveDamage(struct DamageContext *ctx, u16 *medianD
median = maximum = minimum = max(0, gBattleMons[ctx->battlerDef].hp - gBattleMons[ctx->battlerAtk].hp);
break;
case EFFECT_BEAT_UP:
if (GetConfig(CONFIG_BEAT_UP) >= GEN_5)
if (GetConfig(B_BEAT_UP) >= GEN_5)
{
u32 partyCount = CalculatePartyCount(GetBattlerParty(ctx->battlerAtk));
u32 i;
@ -873,7 +873,7 @@ static inline bool32 ShouldCalcCritDamage(u32 battlerAtk, u32 battlerDef, u32 mo
s32 critChanceIndex = 0;
// Get crit chance
if (GetConfig(CONFIG_CRIT_CHANCE) == GEN_1)
if (GetConfig(B_CRIT_CHANCE) == GEN_1)
critChanceIndex = CalcCritChanceStageGen1(battlerAtk, battlerDef, move, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk]);
else
critChanceIndex = CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk]);
@ -882,11 +882,11 @@ static inline bool32 ShouldCalcCritDamage(u32 battlerAtk, u32 battlerDef, u32 mo
return TRUE;
if (critChanceIndex >= RISKY_AI_CRIT_STAGE_THRESHOLD // Not guaranteed but above Risky threshold
&& (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)
&& GetConfig(CONFIG_CRIT_CHANCE) != GEN_1)
&& GetConfig(B_CRIT_CHANCE) != GEN_1)
return TRUE;
if (critChanceIndex >= RISKY_AI_CRIT_THRESHOLD_GEN_1 // Not guaranteed but above Risky threshold
&& (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)
&& GetConfig(CONFIG_CRIT_CHANCE) == GEN_1)
&& GetConfig(B_CRIT_CHANCE) == GEN_1)
return TRUE;
return FALSE;
}
@ -1476,7 +1476,7 @@ bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move)
if (!DoesBattlerIgnoreAbilityChecks(battler, gAiLogicData->abilities[battler], move))
{
if (GetConfig(CONFIG_STURDY) >= GEN_5 && gAiLogicData->abilities[battlerTarget] == ABILITY_STURDY)
if (GetConfig(B_STURDY) >= GEN_5 && gAiLogicData->abilities[battlerTarget] == ABILITY_STURDY)
return TRUE;
if (IsMimikyuDisguised(battlerTarget))
return TRUE;
@ -1830,7 +1830,7 @@ u32 AI_GetSwitchinWeather(struct BattlePokemon battleMon)
case ABILITY_SAND_STREAM:
return B_WEATHER_SANDSTORM;
case ABILITY_SNOW_WARNING:
return GetConfig(CONFIG_SNOW_WARNING) >= GEN_9 ? B_WEATHER_SNOW : B_WEATHER_HAIL;
return GetConfig(B_SNOW_WARNING) >= GEN_9 ? B_WEATHER_SNOW : B_WEATHER_HAIL;
default:
return gBattleWeather;
}
@ -1931,7 +1931,7 @@ bool32 IsHazardClearingMove(u32 move)
case EFFECT_TIDY_UP:
return TRUE;
case EFFECT_DEFOG:
if (GetConfig(CONFIG_DEFOG_EFFECT_CLEARING) >= GEN_6)
if (GetConfig(B_DEFOG_EFFECT_CLEARING) >= GEN_6)
return TRUE;
break;
}
@ -2198,7 +2198,7 @@ bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData,
if (stat == STAT_DEF)
return FALSE;
case ABILITY_ILLUMINATE:
if (GetConfig(CONFIG_ILLUMINATE_EFFECT) < GEN_9)
if (GetConfig(B_ILLUMINATE_EFFECT) < GEN_9)
break;
case ABILITY_KEEN_EYE:
case ABILITY_MINDS_EYE:
@ -2938,7 +2938,7 @@ bool32 IsSwitchOutEffect(enum BattleMoveEffects effect)
switch (effect)
{
case EFFECT_TELEPORT:
if (GetConfig(CONFIG_TELEPORT_BEHAVIOR) >= GEN_8)
if (GetConfig(B_TELEPORT_BEHAVIOR) >= GEN_8)
return TRUE;
case EFFECT_HIT_ESCAPE:
case EFFECT_PARTING_SHOT:
@ -3365,7 +3365,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility
if (!IsBattleMoveStatus(move) && ((gAiLogicData->shouldSwitch & (1u << battlerAtk))
|| (AI_BattlerAtMaxHp(battlerDef) && (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|| (GetConfig(CONFIG_STURDY) >= GEN_5 && defAbility == ABILITY_STURDY)
|| (GetConfig(B_STURDY) >= GEN_5 && defAbility == ABILITY_STURDY)
|| defAbility == ABILITY_MULTISCALE
|| defAbility == ABILITY_SHADOW_SHIELD))))
return SHOULD_PIVOT; // pivot to break sash/sturdy/multiscale
@ -3373,7 +3373,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility
else if (!hasStatBoost)
{
if (!IsBattleMoveStatus(move) && (AI_BattlerAtMaxHp(battlerDef) && (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|| (GetConfig(CONFIG_STURDY) >= GEN_5 && defAbility == ABILITY_STURDY)
|| (GetConfig(B_STURDY) >= GEN_5 && defAbility == ABILITY_STURDY)
|| defAbility == ABILITY_MULTISCALE
|| defAbility == ABILITY_SHADOW_SHIELD)))
return SHOULD_PIVOT; // pivot to break sash/sturdy/multiscale
@ -3829,24 +3829,21 @@ bool32 HasChoiceEffect(u32 battler)
}
}
static u32 FindMoveUsedXTurnsAgo(u32 battlerId, u32 x)
{
s32 i, index = gBattleHistory->moveHistoryIndex[battlerId];
for (i = 0; i < x; i++)
{
if (--index < 0)
index = AI_MOVE_HISTORY_COUNT - 1;
}
return gBattleHistory->moveHistory[battlerId][index];
}
bool32 IsWakeupTurn(u32 battler)
{
// Check if rest was used 2 turns ago
if ((gBattleMons[battler].status1 & STATUS1_SLEEP) == 1 && GetMoveEffect(FindMoveUsedXTurnsAgo(battler, 2)) == EFFECT_REST)
return TRUE;
else // no way to know
u32 sleepTurns = gBattleMons[battler].status1 & STATUS1_SLEEP;
u32 toSub;
if (sleepTurns == 0)
return FALSE;
// Early Bird reduces the sleep timer twice as fast.
if (gAiLogicData->abilities[battler] == ABILITY_EARLY_BIRD)
toSub = 2;
else
toSub = 1;
return sleepTurns <= toSub;
}
bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof)
@ -3862,7 +3859,7 @@ bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof)
battlerOnField1 = gBattlerPartyIndexes[battlerId];
battlerOnField2 = gBattlerPartyIndexes[GetPartnerBattler(battlerId)];
// Check partner's status
if ((GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) == GEN_5
if ((GetConfig(B_HEAL_BELL_SOUNDPROOF) == GEN_5
|| gAiLogicData->abilities[BATTLE_PARTNER(battlerId)] != ABILITY_SOUNDPROOF
|| !checkSoundproof)
&& GetMonData(&party[battlerOnField2], MON_DATA_STATUS) != STATUS1_NONE
@ -3876,8 +3873,8 @@ bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof)
}
// Check attacker's status
if ((GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) == GEN_5
|| GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) >= GEN_8
if ((GetConfig(B_HEAL_BELL_SOUNDPROOF) == GEN_5
|| GetConfig(B_HEAL_BELL_SOUNDPROOF) >= GEN_8
|| gAiLogicData->abilities[battlerId] != ABILITY_SOUNDPROOF || !checkSoundproof)
&& GetMonData(&party[battlerOnField1], MON_DATA_STATUS) != STATUS1_NONE
&& ShouldCureStatus(battlerId, battlerId, gAiLogicData))
@ -3888,7 +3885,7 @@ bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof)
{
if (i == battlerOnField1 || i == battlerOnField2)
continue;
if (GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) < GEN_5
if (GetConfig(B_HEAL_BELL_SOUNDPROOF) < GEN_5
&& checkSoundproof
&& GetMonAbility(&party[i]) == ABILITY_SOUNDPROOF)
continue;
@ -5783,7 +5780,7 @@ bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, enum Ability ability
{
case ABILITY_LIGHTNING_ROD:
case ABILITY_STORM_DRAIN:
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) < GEN_5)
if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) < GEN_5)
return FALSE;
else
return (BattlerStatCanRise(battlerDef, ability, STAT_SPATK) && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL));

View File

@ -1,5 +1,6 @@
#include "global.h"
#include "battle_anim.h"
#include "battle_anim_internal.h"
#include "gpu_regs.h"
#include "trig.h"
#include "constants/rgb.h"
@ -192,27 +193,29 @@ const struct SpriteTemplate gTailGlowOrbSpriteTemplate =
static void AnimMegahornHorn(struct Sprite *sprite)
{
CMD_ARGS(x1, y1, x2, y2, duration);
if (IsContest())
{
StartSpriteAffineAnim(sprite, 2);
gBattleAnimArgs[2] = -gBattleAnimArgs[2];
gBattleAnimArgs[0] = -gBattleAnimArgs[0];
cmd->x2 = -cmd->x2;
cmd->x1 = -cmd->x1;
}
else if (IsOnPlayerSide(gBattleAnimTarget))
{
StartSpriteAffineAnim(sprite, 1);
gBattleAnimArgs[1] = -gBattleAnimArgs[1];
gBattleAnimArgs[2] = -gBattleAnimArgs[2];
gBattleAnimArgs[3] = -gBattleAnimArgs[3];
gBattleAnimArgs[0] = -gBattleAnimArgs[0];
cmd->y1 = -cmd->y1;
cmd->x2 = -cmd->x2;
cmd->y2 = -cmd->y2;
cmd->x1 = -cmd->x1;
}
sprite->x = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_X_2) + gBattleAnimArgs[0];
sprite->y = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + gBattleAnimArgs[1];
sprite->data[0] = gBattleAnimArgs[4];
sprite->x = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_X_2) + cmd->x1;
sprite->y = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + cmd->y1;
sprite->data[0] = cmd->duration;
sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + gBattleAnimArgs[2];
sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + gBattleAnimArgs[3];
sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + cmd->x2;
sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + cmd->y2;
sprite->callback = StartAnimLinearTranslation;
StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
@ -220,20 +223,22 @@ static void AnimMegahornHorn(struct Sprite *sprite)
static void AnimLeechLifeNeedle(struct Sprite *sprite)
{
CMD_ARGS(x, y, duration);
if (IsContest())
{
gBattleAnimArgs[0] = -gBattleAnimArgs[0];
cmd->x = -cmd->x;
StartSpriteAffineAnim(sprite, 2);
}
else if (IsOnPlayerSide(gBattleAnimTarget))
{
gBattleAnimArgs[1] = -gBattleAnimArgs[1];
gBattleAnimArgs[0] = -gBattleAnimArgs[0];
cmd->y = -cmd->y;
cmd->x = -cmd->x;
}
sprite->x = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_X_2) + gBattleAnimArgs[0];
sprite->y = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + gBattleAnimArgs[1];
sprite->data[0] = gBattleAnimArgs[2];
sprite->x = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_X_2) + cmd->x;
sprite->y = GetBattlerSpriteCoord2(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + cmd->y;
sprite->data[0] = cmd->duration;
sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2);
sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET);
@ -244,22 +249,20 @@ static void AnimLeechLifeNeedle(struct Sprite *sprite)
// Creates a single web thread that travels from attacker to target.
// Used by MOVE_STRING_SHOT and MOVE_SPIDER_WEB in their first move phase.
// arg 0: x
// arg 1: y
// arg 2: controls the left-to-right movement
// arg 3: amplitude
// arg 4: if targets both opponents
static void AnimTranslateWebThread(struct Sprite *sprite)
{
CMD_ARGS(x, y, unk2, amplitude, targetsBoth);
if (IsContest())
gBattleAnimArgs[2] /= 2;
cmd->unk2 /= 2;
InitSpritePosToAnimAttacker(sprite, TRUE);
sprite->data[0] = gBattleAnimArgs[2];
sprite->data[0] = cmd->unk2;
sprite->data[1] = sprite->x;
sprite->data[3] = sprite->y;
if (!gBattleAnimArgs[4])
if (!cmd->targetsBoth)
{
sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2);
sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET);
@ -270,7 +273,7 @@ static void AnimTranslateWebThread(struct Sprite *sprite)
}
InitAnimLinearTranslationWithSpeed(sprite);
sprite->data[5] = gBattleAnimArgs[3];
sprite->data[5] = cmd->amplitude;
sprite->callback = AnimTranslateWebThread_Step;
}
@ -289,13 +292,15 @@ static void AnimTranslateWebThread_Step(struct Sprite *sprite)
// Second stage of String Shot
static void AnimStringWrap(struct Sprite *sprite)
{
CMD_ARGS(x, y);
SetAverageBattlerPositions(gBattleAnimTarget, FALSE, &sprite->x, &sprite->y);
if (!IsOnPlayerSide(gBattleAnimAttacker))
sprite->x -= gBattleAnimArgs[0];
sprite->x -= cmd->x;
else
sprite->x += gBattleAnimArgs[0];
sprite->x += cmd->x;
sprite->y += gBattleAnimArgs[1];
sprite->y += cmd->y;
if (IsOnPlayerSide(gBattleAnimTarget))
sprite->y += 8;
@ -365,27 +370,24 @@ static void AnimSpiderWeb_End(struct Sprite *sprite)
// Translates a stinger sprite linearly to a destination location. The sprite is
// initially rotated so that it appears to be traveling in a straight line.
// arg 0: initial x pixel offset
// arg 1: initial y pixel offset
// arg 2: target x pixel offset
// arg 3: target y pixel offset
// arg 4: duration
void AnimTranslateStinger(struct Sprite *sprite)
{
CMD_ARGS(initialX, intialY, targetX, targetY, duration);
s16 lVarX, lVarY;
u16 rot;
if (IsContest())
{
gBattleAnimArgs[2] = -gBattleAnimArgs[2];
cmd->targetX = -cmd->targetX;
}
else
{
if (!IsOnPlayerSide(gBattleAnimAttacker))
{
gBattleAnimArgs[2] = -gBattleAnimArgs[2];
gBattleAnimArgs[1] = -gBattleAnimArgs[1];
gBattleAnimArgs[3] = -gBattleAnimArgs[3];
cmd->targetX = -cmd->targetX;
cmd->intialY = -cmd->intialY;
cmd->targetY = -cmd->targetY;
}
}
@ -394,20 +396,20 @@ void AnimTranslateStinger(struct Sprite *sprite)
if (GetBattlerPosition(gBattleAnimTarget) == B_POSITION_PLAYER_LEFT
|| GetBattlerPosition(gBattleAnimTarget) == B_POSITION_OPPONENT_LEFT)
{
gBattleAnimArgs[2] *= -1;
gBattleAnimArgs[0] *= -1;
cmd->targetX *= -1;
cmd->initialX *= -1;
}
}
InitSpritePosToAnimAttacker(sprite, TRUE);
lVarX = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + gBattleAnimArgs[2];
lVarY = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + gBattleAnimArgs[3];
lVarX = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + cmd->targetX;
lVarY = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + cmd->targetY;
rot = ArcTan2Neg(lVarX - sprite->x, lVarY - sprite->y);
rot += 0xC000;
TrySetSpriteRotScale(sprite, FALSE, 0x100, 0x100, rot);
sprite->data[0] = gBattleAnimArgs[4];
sprite->data[0] = cmd->duration;
sprite->data[2] = lVarX;
sprite->data[4] = lVarY;
@ -416,23 +418,19 @@ void AnimTranslateStinger(struct Sprite *sprite)
}
// Rotates sprite and moves it in an arc, so that it appears like a missle or arrow traveling.
// arg 0: initial x pixel offset
// arg 1: initial y pixel offset
// arg 2: target x pixel offset
// arg 3: target y pixel offset
// arg 4: duration
// arg 5: wave amplitude
void AnimMissileArc(struct Sprite *sprite)
{
CMD_ARGS(initialX, intialY, targetX, targetY, duration, waveAmplitude);
InitSpritePosToAnimAttacker(sprite, TRUE);
if (!IsOnPlayerSide(gBattleAnimAttacker))
gBattleAnimArgs[2] = -gBattleAnimArgs[2];
cmd->targetX = -cmd->targetX;
sprite->data[0] = gBattleAnimArgs[4];
sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + gBattleAnimArgs[2];
sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + gBattleAnimArgs[3];
sprite->data[5] = gBattleAnimArgs[5];
sprite->data[0] = cmd->duration;
sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2) + cmd->targetX;
sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET) + cmd->targetY;
sprite->data[5] = cmd->waveAmplitude;
InitAnimArcTranslation(sprite);
sprite->callback = AnimMissileArc_Step;
@ -478,7 +476,9 @@ void AnimMissileArc_Step(struct Sprite *sprite)
static void AnimTailGlowOrb(struct Sprite *sprite)
{
if (gBattleAnimArgs[0] == ANIM_ATTACKER)
CMD_ARGS(relativeTo);
if (cmd->relativeTo == ANIM_ATTACKER)
{
sprite->x = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET) + 18;

View File

@ -1,5 +1,6 @@
#include "global.h"
#include "battle_anim.h"
#include "battle_anim_internal.h"
#include "contest.h"
#include "gpu_regs.h"
#include "graphics.h"
@ -290,8 +291,10 @@ static void AnimPunishment(struct Sprite *sprite)
void AnimTask_AttackerFadeToInvisible(u8 taskId)
{
CMD_ARGS(stepDelay);
int battler;
gTasks[taskId].data[0] = gBattleAnimArgs[0];
gTasks[taskId].data[0] = cmd->stepDelay;
battler = gBattleAnimAttacker;
gTasks[taskId].data[1] = 16;
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(16, 0));
@ -328,7 +331,9 @@ static void AnimTask_AttackerFadeToInvisible_Step(u8 taskId)
void AnimTask_AttackerFadeFromInvisible(u8 taskId)
{
gTasks[taskId].data[0] = gBattleAnimArgs[0];
CMD_ARGS(stepDelay);
gTasks[taskId].data[0] = cmd->stepDelay;
gTasks[taskId].data[1] = BLDALPHA_BLEND(0, 16);
gTasks[taskId].func = AnimTask_AttackerFadeFromInvisible_Step;
SetGpuReg(REG_OFFSET_BLDALPHA, gTasks[taskId].data[1]);
@ -415,12 +420,14 @@ static void AnimUnusedBagSteal_Step(struct Sprite *sprite)
// Move sprite inward for Bite/Crunch and Clamp
void AnimBite(struct Sprite *sprite)
{
sprite->x += gBattleAnimArgs[0];
sprite->y += gBattleAnimArgs[1];
StartSpriteAffineAnim(sprite, gBattleAnimArgs[2]);
sprite->data[0] = gBattleAnimArgs[3];
sprite->data[1] = gBattleAnimArgs[4];
sprite->data[2] = gBattleAnimArgs[5];
CMD_ARGS(x, y, animation, xVelocity, yVelocity, halfDuration);
sprite->x += cmd->x;
sprite->y += cmd->y;
StartSpriteAffineAnim(sprite, cmd->animation);
sprite->data[0] = cmd->xVelocity;
sprite->data[1] = cmd->yVelocity;
sprite->data[2] = cmd->halfDuration;
sprite->callback = AnimBite_Step1;
}
@ -447,10 +454,12 @@ static void AnimBite_Step2(struct Sprite *sprite)
// Launches a tear drop away from the battler. Used by Fake Tears
void AnimTearDrop(struct Sprite *sprite)
{
CMD_ARGS(relativeTo, type);
u8 battler;
s8 xOffset;
if (gBattleAnimArgs[0] == ANIM_ATTACKER)
if (cmd->relativeTo == ANIM_ATTACKER)
battler = gBattleAnimAttacker;
else
battler = gBattleAnimTarget;
@ -458,7 +467,7 @@ void AnimTearDrop(struct Sprite *sprite)
xOffset = 20;
sprite->oam.tileNum += 4;
switch (gBattleAnimArgs[1])
switch (cmd->type)
{
case 0:
sprite->x = GetBattlerSpriteCoordAttr(battler, BATTLER_COORD_ATTR_RIGHT) - 8;
@ -899,21 +908,22 @@ void AnimTask_MementoHandleBg(u8 taskId)
// Animates a deep slash from a claw. Used by Metal Claw, Dragon Claw, and Crush Claw
void AnimClawSlash(struct Sprite *sprite)
{
sprite->x += gBattleAnimArgs[0];
sprite->y += gBattleAnimArgs[1];
StartSpriteAnim(sprite, gBattleAnimArgs[2]);
CMD_ARGS(x, y, animation);
sprite->x += cmd->x;
sprite->y += cmd->y;
StartSpriteAnim(sprite, cmd->animation);
sprite->callback = RunStoredCallbackWhenAnimEnds;
StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
}
// Makes the attacker metallic and shining.
// Used by MOVE_HARDEN and MOVE_IRON_DEFENSE.
// arg0: if true won't change battler's palette back
// arg1: if true, use custom color
// arg2: custom color
// Custom color argument is used in MOVE_POISON_TAIL to make the mon turn purplish/pinkish as if became cloaked in poison.
void AnimTask_MetallicShine(u8 taskId)
{
CMD_ARGS(permanent, useColor, color);
u16 species;
u8 spriteId;
u8 newSpriteId;
@ -963,15 +973,15 @@ void AnimTask_MetallicShine(u8 taskId)
gBattle_BG1_Y = -gSprites[spriteId].y + 32;
paletteNum = 16 + gSprites[spriteId].oam.paletteNum;
if (gBattleAnimArgs[1] == 0)
if (cmd->useColor == 0)
SetGrayscaleOrOriginalPalette(paletteNum, FALSE);
else
BlendPalette(BG_PLTT_ID(paletteNum), 16, 11, gBattleAnimArgs[2]);
BlendPalette(BG_PLTT_ID(paletteNum), 16, 11, cmd->color);
gTasks[taskId].data[0] = newSpriteId;
gTasks[taskId].data[1] = gBattleAnimArgs[0];
gTasks[taskId].data[2] = gBattleAnimArgs[1];
gTasks[taskId].data[3] = gBattleAnimArgs[2];
gTasks[taskId].data[1] = cmd->permanent;
gTasks[taskId].data[2] = cmd->useColor;
gTasks[taskId].data[3] = cmd->color;
gTasks[taskId].data[6] = priorityChanged;
gTasks[taskId].func = AnimTask_MetallicShine_Step;
}
@ -1020,22 +1030,22 @@ static void AnimTask_MetallicShine_Step(u8 taskId)
}
// Changes battler's palette to either grayscale or original.
// arg0: which battler
// arg1: FALSE grayscale, TRUE original
void AnimTask_SetGrayscaleOrOriginalPal(u8 taskId)
{
CMD_ARGS(battler, mode);
u8 spriteId;
u8 battler;
bool8 calcSpriteId = FALSE;
u8 position = B_POSITION_PLAYER_LEFT;
switch (gBattleAnimArgs[0])
switch (cmd->battler)
{
case ANIM_ATTACKER:
case ANIM_TARGET:
case ANIM_ATK_PARTNER:
case ANIM_DEF_PARTNER:
spriteId = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
spriteId = GetAnimBattlerSpriteId(cmd->battler);
break;
case ANIM_PLAYER_LEFT:
position = B_POSITION_PLAYER_LEFT;
@ -1068,7 +1078,7 @@ void AnimTask_SetGrayscaleOrOriginalPal(u8 taskId)
}
if (spriteId != SPRITE_NONE)
SetGrayscaleOrOriginalPalette(gSprites[spriteId].oam.paletteNum + 16, gBattleAnimArgs[1]);
SetGrayscaleOrOriginalPalette(gSprites[spriteId].oam.paletteNum + 16, cmd->mode);
DestroyAnimVisualTask(taskId);
}

View File

@ -1,5 +1,6 @@
#include "global.h"
#include "battle_anim.h"
#include "battle_anim_internal.h"
#include "scanline_effect.h"
#include "task.h"
#include "trig.h"
@ -404,24 +405,26 @@ static void AnimSpinningDracoMeteor(struct Sprite *sprite)
void AnimOutrageFlame(struct Sprite *sprite)
{
CMD_ARGS(x, y, duration, xVelocity, yVelocity, flickerDuration);
sprite->x = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET);
if (!IsOnPlayerSide(gBattleAnimAttacker))
{
sprite->x -= gBattleAnimArgs[0];
gBattleAnimArgs[3] = -gBattleAnimArgs[3];
gBattleAnimArgs[4] = -gBattleAnimArgs[4];
sprite->x -= cmd->x;
cmd->xVelocity = -cmd->xVelocity;
cmd->yVelocity = -cmd->yVelocity;
}
else
{
sprite->x += gBattleAnimArgs[0];
sprite->x += cmd->x;
}
sprite->y += gBattleAnimArgs[1];
sprite->data[0] = gBattleAnimArgs[2];
sprite->data[1] = gBattleAnimArgs[3];
sprite->data[3] = gBattleAnimArgs[4];
sprite->data[5] = gBattleAnimArgs[5];
sprite->y += cmd->y;
sprite->data[0] = cmd->duration;
sprite->data[1] = cmd->xVelocity;
sprite->data[3] = cmd->yVelocity;
sprite->data[5] = cmd->flickerDuration;
sprite->invisible = TRUE;
StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
sprite->callback = TranslateSpriteLinearAndFlicker;
@ -429,26 +432,28 @@ void AnimOutrageFlame(struct Sprite *sprite)
static void StartDragonFireTranslation(struct Sprite *sprite)
{
CMD_ARGS(initialX, initialY, targetX, targetY, duration);
SetSpriteCoordsToAnimAttackerCoords(sprite);
sprite->data[2] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X_2);
sprite->data[4] = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y_PIC_OFFSET);
if (!IsOnPlayerSide(gBattleAnimAttacker))
{
sprite->x -= gBattleAnimArgs[1];
sprite->y += gBattleAnimArgs[1];
sprite->data[2] -= gBattleAnimArgs[2];
sprite->data[4] += gBattleAnimArgs[3];
sprite->x -= cmd->initialY;
sprite->y += cmd->initialY;
sprite->data[2] -= cmd->targetX;
sprite->data[4] += cmd->targetY;
}
else
{
sprite->x += gBattleAnimArgs[0];
sprite->y += gBattleAnimArgs[1];
sprite->data[2] += gBattleAnimArgs[2];
sprite->data[4] += gBattleAnimArgs[3];
sprite->x += cmd->initialX;
sprite->y += cmd->initialY;
sprite->data[2] += cmd->targetX;
sprite->data[4] += cmd->targetY;
StartSpriteAnim(sprite, 1);
}
sprite->data[0] = gBattleAnimArgs[4];
sprite->data[0] = cmd->duration;
sprite->callback = StartAnimLinearTranslation;
StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
}
@ -458,7 +463,9 @@ static void StartDragonFireTranslation(struct Sprite *sprite)
// args[2] - initial y offset
void AnimDragonRageFirePlume(struct Sprite *sprite)
{
if (gBattleAnimArgs[0] == 0)
CMD_ARGS(relativeTo, x, y);
if (cmd->relativeTo == ANIM_ATTACKER)
{
sprite->x = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X);
sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y);
@ -469,8 +476,8 @@ void AnimDragonRageFirePlume(struct Sprite *sprite)
sprite->y = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y);
}
SetAnimSpriteInitialXOffset(sprite, gBattleAnimArgs[1]);
sprite->y += gBattleAnimArgs[2];
SetAnimSpriteInitialXOffset(sprite, cmd->x);
sprite->y += cmd->y;
sprite->callback = RunStoredCallbackWhenAnimEnds;
StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
}
@ -486,13 +493,15 @@ void AnimDragonFireToTarget(struct Sprite *sprite)
void AnimDragonDanceOrb(struct Sprite *sprite)
{
CMD_ARGS(angle);
u16 r5;
u16 r0;
sprite->x = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET);
sprite->data[4] = 0;
sprite->data[5] = 1;
sprite->data[6] = gBattleAnimArgs[0];
sprite->data[6] = cmd->angle;
r5 = GetBattlerSpriteCoordAttr(gBattlerAttacker, BATTLER_COORD_ATTR_HEIGHT);
r0 = GetBattlerSpriteCoordAttr(gBattlerAttacker, BATTLER_COORD_ATTR_WIDTH);
if (r5 > r0)
@ -633,14 +642,16 @@ static void UpdateDragonDanceScanlineEffect(struct Task *task)
void AnimOverheatFlame(struct Sprite *sprite)
{
int yAmplitude = (gBattleAnimArgs[2] * 3) / 5;
CMD_ARGS(speed, unk1, unk2, duration, y);
int yAmplitude = (cmd->unk2 * 3) / 5;
sprite->x = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2);
sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET) + gBattleAnimArgs[4];
sprite->data[1] = Cos(gBattleAnimArgs[1], gBattleAnimArgs[2]);
sprite->data[2] = Sin(gBattleAnimArgs[1], yAmplitude);
sprite->x += sprite->data[1] * gBattleAnimArgs[0];
sprite->y += sprite->data[2] * gBattleAnimArgs[0];
sprite->data[3] = gBattleAnimArgs[3];
sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET) + cmd->y;
sprite->data[1] = Cos(cmd->unk1, cmd->unk2);
sprite->data[2] = Sin(cmd->unk1, yAmplitude);
sprite->x += sprite->data[1] * cmd->speed;
sprite->y += sprite->data[2] * cmd->speed;
sprite->data[3] = cmd->duration;
sprite->callback = AnimOverheatFlame_Step;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#include "global.h"
#include "battle_anim.h"
#include "battle_anim_internal.h"
#include "palette.h"
#include "random.h"
#include "task.h"
@ -339,29 +340,26 @@ static void AnimMovePowerSwapGuardSwap(struct Sprite *sprite)
}
// Moves a spinning duck around the mon's head.
// arg 0: initial x pixel offset
// arg 1: initial y pixel offset
// arg 2: initial wave offset
// arg 3: wave period (higher means faster wave)
// arg 4: duration
static void AnimConfusionDuck(struct Sprite *sprite)
{
sprite->x += gBattleAnimArgs[0];
sprite->y += gBattleAnimArgs[1];
sprite->data[0] = gBattleAnimArgs[2];
CMD_ARGS(x, y, waveOffset, wavePeriod, duration);
sprite->x += cmd->x;
sprite->y += cmd->y;
sprite->data[0] = cmd->waveOffset;
if (!IsOnPlayerSide(gBattleAnimAttacker))
{
sprite->data[1] = -gBattleAnimArgs[3];
sprite->data[1] = -cmd->wavePeriod;
sprite->data[4] = 1;
}
else
{
sprite->data[1] = gBattleAnimArgs[3];
sprite->data[1] = cmd->wavePeriod;
sprite->data[4] = 0;
StartSpriteAnim(sprite, 1);
}
sprite->data[3] = gBattleAnimArgs[4];
sprite->data[3] = cmd->duration;
sprite->callback = AnimConfusionDuck_Step;
sprite->callback(sprite);
}
@ -382,15 +380,12 @@ static void AnimConfusionDuck_Step(struct Sprite *sprite)
}
// Performs a simple color blend on a specified sprite.
// arg 0: palette selector
// arg 1: delay
// arg 2: start blend amount
// arg 3: end blend amount
// arg 4: blend color
static void AnimSimplePaletteBlend(struct Sprite *sprite)
{
u32 selectedPalettes = UnpackSelectedBattlePalettes(gBattleAnimArgs[0]);
BeginNormalPaletteFade(selectedPalettes, gBattleAnimArgs[1], gBattleAnimArgs[2], gBattleAnimArgs[3], gBattleAnimArgs[4]);
CMD_ARGS(selector, delay, initialBlendY, targetBlendY, color);
u32 selectedPalettes = UnpackSelectedBattlePalettes(cmd->selector);
BeginNormalPaletteFade(selectedPalettes, cmd->delay, cmd->initialBlendY, cmd->targetBlendY, cmd->color);
sprite->invisible = TRUE;
sprite->callback = AnimSimplePaletteBlend_Step;
}
@ -441,21 +436,32 @@ static void AnimSimplePaletteBlend_Step(struct Sprite *sprite)
DestroyAnimSprite(sprite);
}
#define sTimer data[0]
#define sDelay data[1]
#define sNumBlends data[2]
#define sColor1 data[3]
#define sBlendY1 data[4]
#define sColor2 data[5]
#define sBlendY2 data[6]
#define sPaletteSelector data[7]
static void AnimComplexPaletteBlend(struct Sprite *sprite)
{
CMD_ARGS(selector, delay, numBlends, color1, blendY1, color2, blendY2);
u32 selectedPalettes;
sprite->data[0] = gBattleAnimArgs[1];
sprite->data[1] = gBattleAnimArgs[1];
sprite->data[2] = gBattleAnimArgs[2];
sprite->data[3] = gBattleAnimArgs[3];
sprite->data[4] = gBattleAnimArgs[4];
sprite->data[5] = gBattleAnimArgs[5];
sprite->data[6] = gBattleAnimArgs[6];
sprite->data[7] = gBattleAnimArgs[0];
sprite->sTimer = cmd->delay;
sprite->sDelay = cmd->delay;
sprite->sNumBlends = cmd->numBlends;
sprite->sColor1 = cmd->color1;
sprite->sBlendY1 = cmd->blendY1;
sprite->sColor2 = cmd->color2;
sprite->sBlendY2 = cmd->blendY2;
sprite->sPaletteSelector = cmd->selector;
selectedPalettes = UnpackSelectedBattlePalettes(sprite->data[7]);
BlendPalettes(selectedPalettes, gBattleAnimArgs[4], gBattleAnimArgs[3]);
selectedPalettes = UnpackSelectedBattlePalettes(sprite->sPaletteSelector);
BlendPalettes(selectedPalettes, cmd->blendY1, cmd->color1);
sprite->invisible = TRUE;
sprite->callback = AnimComplexPaletteBlend_Step1;
}
@ -464,30 +470,30 @@ static void AnimComplexPaletteBlend_Step1(struct Sprite *sprite)
{
u32 selectedPalettes;
if (sprite->data[0] > 0)
if (sprite->sTimer > 0)
{
sprite->data[0]--;
sprite->sTimer--;
return;
}
if (gPaletteFade.active)
return;
if (sprite->data[2] == 0)
if (sprite->sNumBlends == 0)
{
sprite->callback = AnimComplexPaletteBlend_Step2;
return;
}
selectedPalettes = UnpackSelectedBattlePalettes(sprite->data[7]);
if (sprite->data[1] & 0x100)
BlendPalettes(selectedPalettes, sprite->data[4], sprite->data[3]);
selectedPalettes = UnpackSelectedBattlePalettes(sprite->sPaletteSelector);
if (sprite->sDelay & 0x100)
BlendPalettes(selectedPalettes, sprite->sBlendY1, sprite->sColor1);
else
BlendPalettes(selectedPalettes, sprite->data[6], sprite->data[5]);
BlendPalettes(selectedPalettes, sprite->sBlendY2, sprite->sColor2);
sprite->data[1] ^= 0x100;
sprite->data[0] = sprite->data[1] & 0xFF;
sprite->data[2]--;
sprite->sDelay ^= 0x100;
sprite->sTimer = sprite->sDelay & 0xFF;
sprite->sNumBlends--;
}
static void AnimComplexPaletteBlend_Step2(struct Sprite *sprite)
@ -496,16 +502,27 @@ static void AnimComplexPaletteBlend_Step2(struct Sprite *sprite)
if (!gPaletteFade.active)
{
selectedPalettes = UnpackSelectedBattlePalettes(sprite->data[7]);
selectedPalettes = UnpackSelectedBattlePalettes(sprite->sPaletteSelector);
BlendPalettes(selectedPalettes, 0, 0);
DestroyAnimSprite(sprite);
}
}
#undef sTimer
#undef sDelay
#undef sNumBlends
#undef sColor1
#undef sBlendY1
#undef sColor2
#undef sBlendY2
#undef sPaletteSelector
static void AnimCirclingSparkle(struct Sprite *sprite)
{
sprite->x += gBattleAnimArgs[0];
sprite->y += gBattleAnimArgs[1];
CMD_ARGS(x, y);
sprite->x += cmd->x;
sprite->y += cmd->y;
sprite->data[0] = 0;
sprite->data[1] = 10;
sprite->data[2] = 8;
@ -533,12 +550,14 @@ static void AnimCirclingSparkle(struct Sprite *sprite)
// Many uses of this task only set a tNumBlends of 2, which has the effect of blending to a color and back once
void AnimTask_BlendColorCycle(u8 taskId)
{
gTasks[taskId].tPalSelector = gBattleAnimArgs[0];
gTasks[taskId].tDelay = gBattleAnimArgs[1];
gTasks[taskId].tNumBlends = gBattleAnimArgs[2];
gTasks[taskId].tInitialBlendY = gBattleAnimArgs[3];
gTasks[taskId].tTargetBlendY = gBattleAnimArgs[4];
gTasks[taskId].tBlendColor = gBattleAnimArgs[5];
CMD_ARGS(selector, delay, numBlends, initialBlendY, targetBlendY, color);
gTasks[taskId].tPalSelector = cmd->selector;
gTasks[taskId].tDelay = cmd->delay;
gTasks[taskId].tNumBlends = cmd->numBlends;
gTasks[taskId].tInitialBlendY = cmd->initialBlendY;
gTasks[taskId].tTargetBlendY = cmd->targetBlendY;
gTasks[taskId].tBlendColor = cmd->color;
gTasks[taskId].tRestoreBlend = FALSE;
BlendColorCycle(taskId, 0, gTasks[taskId].tTargetBlendY);
gTasks[taskId].func = AnimTask_BlendColorCycleLoop;
@ -593,15 +612,17 @@ static void AnimTask_BlendColorCycleLoop(u8 taskId)
// See AnimTask_BlendColorCycle. Same, but excludes Attacker and Target
void AnimTask_BlendColorCycleExclude(u8 taskId)
{
CMD_ARGS(unk0, delay, numBlends, initialBlendY, targetBlendY, color);
int battler;
u32 selectedPalettes = 0;
gTasks[taskId].data[0] = gBattleAnimArgs[0];
gTasks[taskId].tDelay = gBattleAnimArgs[1];
gTasks[taskId].tNumBlends = gBattleAnimArgs[2];
gTasks[taskId].tInitialBlendY = gBattleAnimArgs[3];
gTasks[taskId].tTargetBlendY = gBattleAnimArgs[4];
gTasks[taskId].tBlendColor = gBattleAnimArgs[5];
gTasks[taskId].data[0] = cmd->unk0;
gTasks[taskId].tDelay = cmd->delay;
gTasks[taskId].tNumBlends = cmd->numBlends;
gTasks[taskId].tInitialBlendY = cmd->initialBlendY;
gTasks[taskId].tTargetBlendY = cmd->targetBlendY;
gTasks[taskId].tBlendColor = cmd->color;
gTasks[taskId].tRestoreBlend = 0;
for (battler = 0; battler < gBattlersCount; battler++)
@ -610,7 +631,7 @@ void AnimTask_BlendColorCycleExclude(u8 taskId)
selectedPalettes |= 1 << (battler + 16);
}
if (gBattleAnimArgs[0] == 1)
if (cmd->unk0 == 1)
selectedPalettes |= 0xE;
gTasks[taskId].tPalSelectorHi = selectedPalettes >> 16;
@ -668,12 +689,14 @@ static void AnimTask_BlendColorCycleExcludeLoop(u8 taskId)
// See AnimTask_BlendColorCycle. Same, but selects palette by ANIM_TAG_*
void AnimTask_BlendColorCycleByTag(u8 taskId)
{
gTasks[taskId].tPalTag = gBattleAnimArgs[0];
gTasks[taskId].tDelay = gBattleAnimArgs[1];
gTasks[taskId].tNumBlends = gBattleAnimArgs[2];
gTasks[taskId].tInitialBlendY = gBattleAnimArgs[3];
gTasks[taskId].tTargetBlendY = gBattleAnimArgs[4];
gTasks[taskId].tBlendColor = gBattleAnimArgs[5];
CMD_ARGS(tag, delay, numBlends, initialBlendY, targetBlendY, color);
gTasks[taskId].tPalTag = cmd->tag;
gTasks[taskId].tDelay = cmd->delay;
gTasks[taskId].tNumBlends = cmd->numBlends;
gTasks[taskId].tInitialBlendY = cmd->initialBlendY;
gTasks[taskId].tTargetBlendY = cmd->targetBlendY;
gTasks[taskId].tBlendColor = cmd->color;
gTasks[taskId].tRestoreBlend = FALSE;
BlendColorCycleByTag(taskId, 0, gTasks[taskId].tTargetBlendY);
@ -738,26 +761,36 @@ static void AnimTask_BlendColorCycleByTagLoop(u8 taskId)
#undef tPalSelectorLo
// Flashes the specified anim tag with given color. Used e.g. to flash the particles red in Hyper Beam
#define tTimer data[0]
#define tDelay data[1]
#define tNumBlends data[2]
#define tColor1 data[3]
#define tBlendY1 data[4]
#define tColor2 data[5]
#define tBlendY2 data[6]
#define tAnimTag data[7]
void AnimTask_FlashAnimTagWithColor(u8 taskId)
{
CMD_ARGS(tag, delay, numBlends, color1, blendY1, color2, blendY2);
u8 paletteIndex;
gTasks[taskId].data[0] = gBattleAnimArgs[1];
gTasks[taskId].data[1] = gBattleAnimArgs[1];
gTasks[taskId].data[2] = gBattleAnimArgs[2];
gTasks[taskId].data[3] = gBattleAnimArgs[3];
gTasks[taskId].data[4] = gBattleAnimArgs[4];
gTasks[taskId].data[5] = gBattleAnimArgs[5];
gTasks[taskId].data[6] = gBattleAnimArgs[6];
gTasks[taskId].data[7] = gBattleAnimArgs[0];
gTasks[taskId].tTimer = cmd->delay;
gTasks[taskId].tDelay = cmd->delay;
gTasks[taskId].tNumBlends = cmd->numBlends;
gTasks[taskId].tColor1 = cmd->color1;
gTasks[taskId].tBlendY1 = cmd->blendY1;
gTasks[taskId].tColor2 = cmd->color2;
gTasks[taskId].tBlendY2 = cmd->blendY2;
gTasks[taskId].tAnimTag = cmd->tag;
paletteIndex = IndexOfSpritePaletteTag(gBattleAnimArgs[0]);
paletteIndex = IndexOfSpritePaletteTag(cmd->tag);
BeginNormalPaletteFade(
1 << (paletteIndex + 16),
0,
gBattleAnimArgs[4],
gBattleAnimArgs[4],
gBattleAnimArgs[3]);
cmd->blendY1,
cmd->blendY1,
cmd->color1);
gTasks[taskId].func = AnimTask_FlashAnimTagWithColor_Step1;
}
@ -766,44 +799,44 @@ static void AnimTask_FlashAnimTagWithColor_Step1(u8 taskId)
{
u32 selectedPalettes;
if (gTasks[taskId].data[0] > 0)
if (gTasks[taskId].tTimer > 0)
{
gTasks[taskId].data[0]--;
gTasks[taskId].tTimer--;
return;
}
if (gPaletteFade.active)
return;
if (gTasks[taskId].data[2] == 0)
if (gTasks[taskId].tNumBlends == 0)
{
gTasks[taskId].func = AnimTask_FlashAnimTagWithColor_Step2;
return;
}
selectedPalettes = 1 << (IndexOfSpritePaletteTag(gTasks[taskId].data[7]) + 16);
if (gTasks[taskId].data[1] & 0x100)
selectedPalettes = 1 << (IndexOfSpritePaletteTag(gTasks[taskId].tAnimTag) + 16);
if (gTasks[taskId].tDelay & 0x100)
{
BeginNormalPaletteFade(
selectedPalettes,
0,
gTasks[taskId].data[4],
gTasks[taskId].data[4],
gTasks[taskId].data[3]);
gTasks[taskId].tBlendY1,
gTasks[taskId].tBlendY1,
gTasks[taskId].tColor1);
}
else
{
BeginNormalPaletteFade(
selectedPalettes,
0,
gTasks[taskId].data[6],
gTasks[taskId].data[6],
gTasks[taskId].data[5]);
gTasks[taskId].tBlendY2,
gTasks[taskId].tBlendY2,
gTasks[taskId].tColor2);
}
gTasks[taskId].data[1] ^= 0x100;
gTasks[taskId].data[0] = gTasks[taskId].data[1] & 0xFF;
gTasks[taskId].data[2]--;
gTasks[taskId].tDelay ^= 0x100;
gTasks[taskId].tTimer = gTasks[taskId].tDelay & 0xFF;
gTasks[taskId].tNumBlends--;
}
static void AnimTask_FlashAnimTagWithColor_Step2(u8 taskId)
@ -812,25 +845,37 @@ static void AnimTask_FlashAnimTagWithColor_Step2(u8 taskId)
if (!gPaletteFade.active)
{
selectedPalettes = 1 << (IndexOfSpritePaletteTag(gTasks[taskId].data[7]) + 16);
selectedPalettes = 1 << (IndexOfSpritePaletteTag(gTasks[taskId].tAnimTag) + 16);
BeginNormalPaletteFade(selectedPalettes, 0, 0, 0, RGB_BLACK);
DestroyAnimVisualTask(taskId);
}
}
#undef tTimer
#undef tDelay
#undef tNumBlends
#undef tColor1
#undef tBlendY1
#undef tColor2
#undef tBlendY2
#undef tAnimTag
// This function is different compared to pret, and flagsScenery doesn't properly describe what the variable is doing on expansion
void AnimTask_InvertScreenColor(u8 taskId)
{
CMD_ARGS(flagsScenery);
u32 selectedPalettes = 0;
if (gBattleAnimArgs[0] & 0x1)
if (cmd->flagsScenery & 0x1)
selectedPalettes = GetBattlePalettesMask(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE);
if (gBattleAnimArgs[0] & 0x2)
if (cmd->flagsScenery & 0x2)
selectedPalettes |= (0x10000 << gBattleAnimAttacker);
if (gBattleAnimArgs[0] & 0x4)
if (cmd->flagsScenery & 0x4)
selectedPalettes |= (0x10000 << gBattleAnimTarget);
if (gBattleAnimArgs[0] & 0x8 && IsBattlerAlive(BATTLE_PARTNER(gBattleAnimTarget)))
if (cmd->flagsScenery & 0x8 && IsBattlerAlive(BATTLE_PARTNER(gBattleAnimTarget)))
selectedPalettes |= (0x10000 << BATTLE_PARTNER(gBattleAnimTarget));
if (gBattleAnimArgs[0] & 0x10 && IsBattlerAlive(BATTLE_PARTNER(gBattleAnimAttacker)))
if (cmd->flagsScenery & 0x10 && IsBattlerAlive(BATTLE_PARTNER(gBattleAnimAttacker)))
selectedPalettes |= (0x10000 << BATTLE_PARTNER(gBattleAnimAttacker));
InvertPlttBuffer(selectedPalettes);
@ -848,6 +893,8 @@ void AnimTask_InvertScreenColor(u8 taskId)
#define tColorB data[7]
void AnimTask_TintPalettes(u8 taskId)
{
CMD_ARGS(flagsScenery, flagsAttacker, flagsTarget, duration, r, g, b);
u8 attackerBattler;
u8 targetBattler;
u8 paletteIndex;
@ -855,13 +902,13 @@ void AnimTask_TintPalettes(u8 taskId)
if (gTasks[taskId].tTimer == 0)
{
gTasks[taskId].tFlagsScenery = gBattleAnimArgs[0];
gTasks[taskId].tFlagsAttacker = gBattleAnimArgs[1];
gTasks[taskId].tFlagsTarget = gBattleAnimArgs[2];
gTasks[taskId].tLength = gBattleAnimArgs[3];
gTasks[taskId].tColorR = gBattleAnimArgs[4];
gTasks[taskId].tColorG = gBattleAnimArgs[5];
gTasks[taskId].tColorB = gBattleAnimArgs[6];
gTasks[taskId].tFlagsScenery = cmd->flagsScenery;
gTasks[taskId].tFlagsAttacker = cmd->flagsAttacker;
gTasks[taskId].tFlagsTarget = cmd->flagsTarget;
gTasks[taskId].tLength = cmd->duration;
gTasks[taskId].tColorR = cmd->r;
gTasks[taskId].tColorG = cmd->g;
gTasks[taskId].tColorB = cmd->b;
}
gTasks[taskId].tTimer++;
@ -899,25 +946,34 @@ void AnimTask_TintPalettes(u8 taskId)
#undef tColorG
#undef tColorB
#define sShakeVelocity data[0]
#define sShakeTimer data[1]
#define sShakeDuration data[2]
#define sTimer data[3]
#define sOriginalValue data[4]
#define sType data[5]
#define sShakePtrLo data[6]
#define sShakePtrHi data[7]
static void AnimShakeMonOrBattlePlatforms(struct Sprite *sprite)
{
u16 var0;
CMD_ARGS(velocity, shakeTimer, shakeDuration, type, battlerSelector);
sprite->invisible = TRUE;
sprite->data[0] = -gBattleAnimArgs[0];
sprite->data[1] = gBattleAnimArgs[1];
sprite->data[2] = gBattleAnimArgs[1];
sprite->data[3] = gBattleAnimArgs[2];
sprite->sShakeVelocity = -cmd->velocity;
sprite->sShakeTimer = cmd->shakeTimer;
sprite->sShakeDuration = cmd->shakeTimer;
sprite->sTimer = cmd->shakeDuration;
switch (gBattleAnimArgs[3])
switch (cmd->type)
{
case 0:
case SHAKE_BG_X:
StoreSpriteCallbackInData6(sprite, (void *)&gBattle_BG3_X);
break;
case 1:
case SHAKE_BG_Y:
StoreSpriteCallbackInData6(sprite, (void *)&gBattle_BG3_Y);
break;
case 2:
case SHAKE_MON_X:
StoreSpriteCallbackInData6(sprite, (void *)&gSpriteCoordOffsetX);
break;
default:
@ -925,10 +981,9 @@ static void AnimShakeMonOrBattlePlatforms(struct Sprite *sprite)
break;
}
sprite->data[4] = *(u16 *)(sprite->data[6] | (sprite->data[7] << 16));
sprite->data[5] = gBattleAnimArgs[3];
var0 = sprite->data[5] - 2;
if (var0 < 2)
sprite->sOriginalValue = *(u16 *)(sprite->sShakePtrLo | (sprite->sShakePtrHi << 16));
sprite->sType = cmd->type;
if (sprite->sType == SHAKE_MON_X || sprite->sType == SHAKE_MON_Y)
AnimShakeMonOrBattlePlatforms_UpdateCoordOffsetEnabled();
sprite->callback = AnimShakeMonOrBattlePlatforms_Step;
@ -937,27 +992,25 @@ static void AnimShakeMonOrBattlePlatforms(struct Sprite *sprite)
static void AnimShakeMonOrBattlePlatforms_Step(struct Sprite *sprite)
{
u8 i;
u16 var0;
if (sprite->data[3] > 0)
if (sprite->sTimer > 0)
{
sprite->data[3]--;
if (sprite->data[1] > 0)
sprite->sTimer--;
if (sprite->sShakeTimer > 0)
{
sprite->data[1]--;
sprite->sShakeTimer--;
}
else
{
sprite->data[1] = sprite->data[2];
*(u16 *)(sprite->data[6] | (sprite->data[7] << 16)) += sprite->data[0];
sprite->data[0] = -sprite->data[0];
sprite->sShakeTimer = sprite->sShakeDuration;
*(u16 *)(sprite->sShakePtrLo | (sprite->sShakePtrHi << 16)) += sprite->sShakeVelocity;
sprite->sShakeVelocity = -sprite->sShakeVelocity;
}
}
else
{
*(u16 *)(sprite->data[6] | (sprite->data[7] << 16)) = sprite->data[4];
var0 = sprite->data[5] - 2;
if (var0 < 2)
*(u16 *)(sprite->sShakePtrLo | (sprite->sShakePtrHi << 16)) = sprite->sOriginalValue;
if (sprite->sType == SHAKE_MON_X || sprite->sType == SHAKE_MON_Y)
{
for (i = 0; i < gBattlersCount; i++)
gSprites[gBattlerSpriteIds[i]].coordOffsetEnabled = FALSE;
@ -969,23 +1022,35 @@ static void AnimShakeMonOrBattlePlatforms_Step(struct Sprite *sprite)
static void AnimShakeMonOrBattlePlatforms_UpdateCoordOffsetEnabled(void)
{
// Matches AnimShakeMonOrBattlePlatforms.
CMD_ARGS(velocity, shakeDuration, duration, type, battlerSelector);
gSprites[gBattlerSpriteIds[gBattleAnimAttacker]].coordOffsetEnabled = FALSE;
gSprites[gBattlerSpriteIds[gBattleAnimTarget]].coordOffsetEnabled = FALSE;
if (gBattleAnimArgs[4] == 2)
if (cmd->battlerSelector == 2)
{
gSprites[gBattlerSpriteIds[gBattleAnimAttacker]].coordOffsetEnabled = TRUE;
gSprites[gBattlerSpriteIds[gBattleAnimTarget]].coordOffsetEnabled = TRUE;
}
else
{
if (gBattleAnimArgs[4] == 0)
if (cmd->battlerSelector == 0)
gSprites[gBattlerSpriteIds[gBattleAnimAttacker]].coordOffsetEnabled = TRUE;
else
gSprites[gBattlerSpriteIds[gBattleAnimTarget]].coordOffsetEnabled = TRUE;
}
}
#undef sShakeVelocity
#undef sShakeTimer
#undef sShakeDuration
#undef sTimer
#undef sOriginalValue
#undef sType
#undef sShakePtrLo
#undef sShakePtrHi
// Task data for AnimTask_ShakeBattlePlatforms
#define tXOffset data[0]
#define tYOffset data[1]
@ -994,19 +1059,17 @@ static void AnimShakeMonOrBattlePlatforms_UpdateCoordOffsetEnabled(void)
#define tShakeDelay data[8]
// Can shake battle platforms back and forth on the X or down and back to original pos on Y (cant shake up from orig pos)
// arg0: x offset of shake
// arg1: y offset of shake
// arg2: number of shakes
// arg3: time between shakes
void AnimTask_ShakeBattlePlatforms(u8 taskId)
{
gTasks[taskId].tXOffset = gBattleAnimArgs[0];
gTasks[taskId].tYOffset = gBattleAnimArgs[1];
gTasks[taskId].tNumShakes = gBattleAnimArgs[2];
gTasks[taskId].tTimer = gBattleAnimArgs[3];
gTasks[taskId].tShakeDelay = gBattleAnimArgs[3];
gBattle_BG3_X = gBattleAnimArgs[0];
gBattle_BG3_Y = gBattleAnimArgs[1];
CMD_ARGS(xOffset, yOffset, shakes, delay);
gTasks[taskId].tXOffset = cmd->xOffset;
gTasks[taskId].tYOffset = cmd->yOffset;
gTasks[taskId].tNumShakes = cmd->shakes;
gTasks[taskId].tTimer = cmd->delay;
gTasks[taskId].tShakeDelay = cmd->delay;
gBattle_BG3_X = cmd->xOffset;
gBattle_BG3_Y = cmd->yOffset;
gTasks[taskId].func = AnimTask_ShakeBattlePlatforms_Step;
gTasks[taskId].func(taskId);
}
@ -1051,8 +1114,10 @@ static void AnimTask_ShakeBattlePlatforms_Step(u8 taskId)
// args[3] - affine anim number
void AnimHitSplatBasic(struct Sprite *sprite)
{
StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);
if (gBattleAnimArgs[2] == ANIM_ATTACKER)
CMD_ARGS(x, y, relativeTo, animation);
StartSpriteAffineAnim(sprite, cmd->animation);
if (cmd->relativeTo == ANIM_ATTACKER)
InitSpritePosToAnimAttacker(sprite, TRUE);
else
InitSpritePosToAnimTarget(sprite, TRUE);
@ -1061,16 +1126,18 @@ void AnimHitSplatBasic(struct Sprite *sprite)
StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
}
// Same as basic hit splat but takes a length of time to persist for (arg4)
// Same as basic hit splat but takes a length of time to persist for.
static void AnimHitSplatPersistent(struct Sprite *sprite)
{
StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);
if (gBattleAnimArgs[2] == ANIM_ATTACKER)
CMD_ARGS(x, y, relativeTo, animation, duration);
StartSpriteAffineAnim(sprite, cmd->animation);
if (cmd->relativeTo == ANIM_ATTACKER)
InitSpritePosToAnimAttacker(sprite, TRUE);
else
InitSpritePosToAnimTarget(sprite, TRUE);
sprite->data[0] = gBattleAnimArgs[4];
sprite->data[0] = cmd->duration;
sprite->callback = RunStoredCallbackWhenAffineAnimEnds;
StoreSpriteCallbackInData6(sprite, DestroyAnimSpriteAfterTimer);
}
@ -1079,20 +1146,25 @@ static void AnimHitSplatPersistent(struct Sprite *sprite)
// Used by Twineedle and Spike Cannon
static void AnimHitSplatHandleInvert(struct Sprite *sprite)
{
// Matches AnimHitSplatBasic.
CMD_ARGS(x, y, relativeTo, animation);
if (!IsOnPlayerSide(gBattleAnimAttacker) && !IsContest())
gBattleAnimArgs[1] = -gBattleAnimArgs[1];
cmd->y = -cmd->y;
AnimHitSplatBasic(sprite);
}
void AnimHitSplatRandom(struct Sprite *sprite)
{
if (gBattleAnimArgs[1] == -1)
gBattleAnimArgs[1] = Random2() & 3;
CMD_ARGS(relativeTo, animation);
if (!InitSpritePosToAnimBattler(gBattleAnimArgs[0], sprite, FALSE))
if (cmd->animation == -1)
cmd->animation = Random2() & 3;
if (!InitSpritePosToAnimBattler(cmd->relativeTo, sprite, FALSE))
return;
StartSpriteAffineAnim(sprite, gBattleAnimArgs[1]);
StartSpriteAffineAnim(sprite, cmd->animation);
sprite->x2 += (Random2() % 48) - 24;
sprite->y2 += (Random2() % 24) - 12;
@ -1103,32 +1175,38 @@ void AnimHitSplatRandom(struct Sprite *sprite)
void AnimHitSplatOnMonEdge(struct Sprite *sprite)
{
sprite->data[0] = GetAnimBattlerSpriteId(gBattleAnimArgs[0]);
CMD_ARGS(relativeTo, x, y, animation);
sprite->data[0] = GetAnimBattlerSpriteId(cmd->relativeTo);
sprite->x = gSprites[sprite->data[0]].x + gSprites[sprite->data[0]].x2;
sprite->y = gSprites[sprite->data[0]].y + gSprites[sprite->data[0]].y2;
sprite->x2 = gBattleAnimArgs[1];
sprite->y2 = gBattleAnimArgs[2];
StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);
sprite->x2 = cmd->x;
sprite->y2 = cmd->y;
StartSpriteAffineAnim(sprite, cmd->animation);
StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
sprite->callback = RunStoredCallbackWhenAffineAnimEnds;
}
void AnimCrossImpact(struct Sprite *sprite)
{
if (gBattleAnimArgs[2] == ANIM_ATTACKER)
CMD_ARGS(x, y, relativeTo, duration);
if (cmd->relativeTo == ANIM_ATTACKER)
InitSpritePosToAnimAttacker(sprite, TRUE);
else
InitSpritePosToAnimTarget(sprite, TRUE);
sprite->data[0] = gBattleAnimArgs[3];
sprite->data[0] = cmd->duration;
StoreSpriteCallbackInData6(sprite, DestroyAnimSprite);
sprite->callback = WaitAnimForDuration;
}
void AnimFlashingHitSplat(struct Sprite *sprite)
{
StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);
if (gBattleAnimArgs[2] == ANIM_ATTACKER)
CMD_ARGS(x, y, relativeTo, animation);
StartSpriteAffineAnim(sprite, cmd->animation);
if (cmd->relativeTo == ANIM_ATTACKER)
InitSpritePosToAnimAttacker(sprite, TRUE);
else
InitSpritePosToAnimTarget(sprite, TRUE);

View File

@ -270,7 +270,7 @@ static bool32 HandleEndTurnWish(u32 battler)
s32 wishHeal = 0;
gBattlerTarget = battler;
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, battler, gWishFutureKnock.wishPartyId[battler])
if (GetConfig(CONFIG_WISH_HP_SOURCE) >= GEN_5)
if (GetConfig(B_WISH_HP_SOURCE) >= GEN_5)
{
if (IsOnPlayerSide(battler))
wishHeal = GetMonData(&gPlayerParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2;
@ -531,7 +531,7 @@ static bool32 HandleEndTurnBurn(u32 battler)
&& IsBattlerAlive(battler)
&& !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD))
{
s32 burnDamage = GetNonDynamaxMaxHP(battler) / ((GetConfig(CONFIG_BURN_DAMAGE) >= GEN_7 || GetConfig(CONFIG_BURN_DAMAGE) == GEN_1) ? 16 : 8);
s32 burnDamage = GetNonDynamaxMaxHP(battler) / ((GetConfig(B_BURN_DAMAGE) >= GEN_7 || GetConfig(B_BURN_DAMAGE) == GEN_1) ? 16 : 8);
if (ability == ABILITY_HEATPROOF)
{
if (burnDamage > (burnDamage / 2) + 1) // Record ability if the burn takes less damage than it normally would.
@ -556,7 +556,7 @@ static bool32 HandleEndTurnFrostbite(u32 battler)
&& IsBattlerAlive(battler)
&& !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
{
SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / ((GetConfig(CONFIG_BURN_DAMAGE) >= GEN_7 || GetConfig(CONFIG_BURN_DAMAGE) == GEN_1) ? 16 : 8));
SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / ((GetConfig(B_BURN_DAMAGE) >= GEN_7 || GetConfig(B_BURN_DAMAGE) == GEN_1) ? 16 : 8));
BattleScriptExecute(BattleScript_FrostbiteTurnDmg);
effect = TRUE;
}

View File

@ -891,17 +891,42 @@ static u32 ItemRestorePp(u32 battler, u32 itemId, ActivationTiming timing)
{
enum ItemEffect effect = ITEM_NO_EFFECT;
struct Pokemon *mon = GetBattlerMon(battler);
u32 i, changedPP = 0;
u32 changedPP = 0;
u32 restoreMove = MAX_MON_MOVES;
u32 missingMove = MAX_MON_MOVES;
u32 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES);
bool32 override = gBattleScripting.overrideBerryRequirements;
enum Ability ability = GetBattlerAbility(battler);
for (i = 0; i < MAX_MON_MOVES; i++)
for (u32 i = 0; i < MAX_MON_MOVES; i++)
{
u32 move = GetMonData(mon, MON_DATA_MOVE1 + i);
u32 currentPP = GetMonData(mon, MON_DATA_PP1 + i);
u32 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES);
u32 maxPP = CalculatePPWithBonus(move, ppBonuses, i);
if (move && (currentPP == 0 || (gBattleScripting.overrideBerryRequirements && currentPP != maxPP)))
if (move == MOVE_NONE)
continue;
if (currentPP == 0)
{
restoreMove = i;
break;
}
if (override && missingMove == MAX_MON_MOVES)
{
u32 maxPP = CalculatePPWithBonus(move, ppBonuses, i);
if (currentPP < maxPP)
missingMove = i;
}
}
if (restoreMove == MAX_MON_MOVES && override)
restoreMove = missingMove;
if (restoreMove != MAX_MON_MOVES)
{
u32 move = GetMonData(mon, MON_DATA_MOVE1 + restoreMove);
u32 currentPP = GetMonData(mon, MON_DATA_PP1 + restoreMove);
u32 maxPP = CalculatePPWithBonus(move, ppBonuses, restoreMove);
u32 ppRestored = GetItemHoldEffectParam(itemId);
if (ability == ABILITY_RIPEN)
@ -909,10 +934,9 @@ static u32 ItemRestorePp(u32 battler, u32 itemId, ActivationTiming timing)
ppRestored *= 2;
gBattlerAbility = battler;
}
if (currentPP + ppRestored > maxPP)
changedPP = maxPP;
else
changedPP = currentPP + ppRestored;
if (changedPP > maxPP)
changedPP = maxPP;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, move);
@ -922,13 +946,12 @@ static u32 ItemRestorePp(u32 battler, u32 itemId, ActivationTiming timing)
BattleScriptCall(BattleScript_BerryPPHealRet);
gBattleScripting.battler = battler;
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP);
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, restoreMove + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP);
MarkBattlerForControllerExec(battler);
if (MOVE_IS_PERMANENT(battler, i))
gBattleMons[battler].pp[i] = changedPP;
if (MOVE_IS_PERMANENT(battler, restoreMove))
gBattleMons[battler].pp[restoreMove] = changedPP;
effect = ITEM_PP_CHANGE;
}
}
return effect;
}

View File

@ -3010,7 +3010,7 @@ static void ClearSetBScriptingStruct(void)
gBattleScripting.battleStyle = OPTIONS_BATTLE_STYLE_SET;
else
gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle;
gBattleScripting.expOnCatch = (GetConfig(CONFIG_EXP_CATCH) >= GEN_6);
gBattleScripting.expOnCatch = (GetConfig(B_EXP_CATCH) >= GEN_6);
gBattleScripting.specialTrainerBattleType = specialBattleType;
}
@ -3304,8 +3304,10 @@ const u8* FaintClearSetData(u32 battler)
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
bool32 keepGastroAcid = gBattleMons[battler].volatiles.gastroAcid;
bool32 keepTransformed = gBattleMons[battler].volatiles.transformed;
memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles));
gBattleMons[battler].volatiles.gastroAcid = keepGastroAcid; // Edge case: Keep Gastro Acid if pokemon's ability can have effect after fainting, for example Innards Out.
gBattleMons[battler].volatiles.transformed = keepTransformed; // Edge case: Keep Transformed status to prevent triggering FORM_CHANGE_FAINT on transformed mons.
for (i = 0; i < gBattlersCount; i++)
{
@ -4106,7 +4108,7 @@ u8 IsRunningFromBattleImpossible(u32 battler)
if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)
return BATTLE_RUN_SUCCESS;
if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
if (GetConfig(B_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
return BATTLE_RUN_SUCCESS;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
return BATTLE_RUN_SUCCESS;
@ -4273,7 +4275,7 @@ static void HandleTurnActionSelectionState(void)
gBattleStruct->moveTarget[battler] = gBattleResources->bufferB[battler][3];
return;
}
else if (GetConfig(CONFIG_ENCORE_TARGET) < GEN_5 && gDisableStructs[battler].encoredMove != MOVE_NONE)
else if (GetConfig(B_ENCORE_TARGET) < GEN_5 && gDisableStructs[battler].encoredMove != MOVE_NONE)
{
gChosenMoveByBattler[battler] = gDisableStructs[battler].encoredMove;
gBattleStruct->chosenMovePositions[battler] = gDisableStructs[battler].encoredMovePos;
@ -4815,7 +4817,7 @@ u32 GetBattlerTotalSpeedStat(u32 battler, enum Ability ability, enum HoldEffect
// paralysis drop
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS && ability != ABILITY_QUICK_FEET)
speed /= GetConfig(CONFIG_PARALYSIS_SPEED) >= GEN_7 ? 2 : 4;
speed /= GetConfig(B_PARALYSIS_SPEED) >= GEN_7 ? 2 : 4;
if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SWAMP)
speed /= 4;
@ -4854,7 +4856,7 @@ s32 GetBattleMovePriority(u32 battler, enum Ability ability, u32 move)
priority = -8;
}
else if (ability == ABILITY_GALE_WINGS
&& (GetConfig(CONFIG_GALE_WINGS) < GEN_7 || IsBattlerAtMaxHp(battler))
&& (GetConfig(B_GALE_WINGS) < GEN_7 || IsBattlerAtMaxHp(battler))
&& GetMoveType(move) == TYPE_FLYING)
{
priority++;
@ -5212,7 +5214,7 @@ static bool32 TryDoGimmicksBeforeMoves(void)
}
}
if (GetConfig(CONFIG_MEGA_EVO_TURN_ORDER) >= GEN_7)
if (GetConfig(B_MEGA_EVO_TURN_ORDER) >= GEN_7)
TryChangeTurnOrder(); // This will just do nothing if no mon has mega evolved.
return FALSE;
}

View File

@ -862,7 +862,7 @@ static bool8 DoesTypePreventStatus(u16 species, u32 status)
break;
case STATUS1_PARALYSIS:
if (GetSpeciesType(species, 0) == TYPE_GROUND || GetSpeciesType(species, 1) == TYPE_GROUND
|| (GetConfig(CONFIG_PARALYZE_ELECTRIC) >= GEN_6 && (GetSpeciesType(species, 0) == TYPE_ELECTRIC || GetSpeciesType(species, 1) == TYPE_ELECTRIC)))
|| (GetConfig(B_PARALYZE_ELECTRIC) >= GEN_6 && (GetSpeciesType(species, 0) == TYPE_ELECTRIC || GetSpeciesType(species, 1) == TYPE_ELECTRIC)))
ret = TRUE;
break;
case STATUS1_BURN:

View File

@ -1584,11 +1584,11 @@ static const u32 sGen2CriticalHitOdds[] = {17, 32, 64, 85, 128}; // X/256
static inline u32 GetCriticalHitOdds(u32 critChance)
{
if (GetConfig(CONFIG_CRIT_CHANCE) >= GEN_7)
if (GetConfig(B_CRIT_CHANCE) >= GEN_7)
return sGen7CriticalHitOdds[critChance];
if (GetConfig(CONFIG_CRIT_CHANCE) == GEN_6)
if (GetConfig(B_CRIT_CHANCE) == GEN_6)
return sGen6CriticalHitOdds[critChance];
if (GetConfig(CONFIG_CRIT_CHANCE) == GEN_2)
if (GetConfig(B_CRIT_CHANCE) == GEN_2)
return sGen2CriticalHitOdds[critChance];
return sCriticalHitOdds[critChance];
@ -1765,7 +1765,7 @@ static void Cmd_critcalc(void)
enum Ability abilityDef = GetBattlerAbility(battlerDef);
enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker);
if (GetConfig(CONFIG_CRIT_CHANCE) == GEN_1)
if (GetConfig(B_CRIT_CHANCE) == GEN_1)
gBattleStruct->critChance[battlerDef] = CalcCritChanceStageGen1(gBattlerAttacker, battlerDef, gCurrentMove, TRUE, abilityAtk, abilityDef, holdEffectAtk);
else
gBattleStruct->critChance[battlerDef] = CalcCritChanceStage(gBattlerAttacker, battlerDef, gCurrentMove, TRUE, abilityAtk, abilityDef, holdEffectAtk);
@ -1778,9 +1778,9 @@ static void Cmd_critcalc(void)
gSpecialStatuses[battlerDef].criticalHit = TRUE;
else
{
if (GetConfig(CONFIG_CRIT_CHANCE) == GEN_1)
if (GetConfig(B_CRIT_CHANCE) == GEN_1)
gSpecialStatuses[battlerDef].criticalHit = RandomChance(RNG_CRITICAL_HIT, gBattleStruct->critChance[battlerDef], 256);
else if (GetConfig(CONFIG_CRIT_CHANCE) == GEN_2)
else if (GetConfig(B_CRIT_CHANCE) == GEN_2)
gSpecialStatuses[battlerDef].criticalHit = RandomChance(RNG_CRITICAL_HIT, GetCriticalHitOdds(gBattleStruct->critChance[battlerDef]), 256);
else
gSpecialStatuses[battlerDef].criticalHit = RandomChance(RNG_CRITICAL_HIT, 1, GetCriticalHitOdds(gBattleStruct->critChance[battlerDef]));
@ -1949,7 +1949,7 @@ static void Cmd_adjustdamage(void)
gLastUsedItem = gBattleMons[battlerDef].item;
gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_FOE_HUNG_ON;
}
else if (GetConfig(CONFIG_STURDY) >= GEN_5 && GetBattlerAbility(battlerDef) == ABILITY_STURDY && IsBattlerAtMaxHp(battlerDef))
else if (GetConfig(B_STURDY) >= GEN_5 && GetBattlerAbility(battlerDef) == ABILITY_STURDY && IsBattlerAtMaxHp(battlerDef))
{
enduredHit |= 1u << battlerDef;
RecordAbilityBattle(battlerDef, ABILITY_STURDY);
@ -2418,7 +2418,7 @@ static void MoveDamageDataHpUpdate(u32 battler, u32 scriptBattler, const u8 *nex
gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED_TOTEM;
else
gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED;
if (GetConfig(CONFIG_DISGUISE_HP_LOSS) >= GEN_8)
if (GetConfig(B_DISGUISE_HP_LOSS) >= GEN_8)
SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8);
BattleScriptPush(nextInstr);
gBattlescriptCurrInstr = BattleScript_TargetFormChange;
@ -2851,7 +2851,7 @@ static void Cmd_printselectionstringfromtable(void)
bool32 HasBattlerActedThisTurn(u32 battler)
{
u32 i;
for (i = 0; i < gCurrentTurnActionNumber; i++)
for (i = 0; i <= gCurrentTurnActionNumber; i++)
{
if (gBattlerByTurnOrder[i] == battler)
return TRUE;
@ -2882,7 +2882,7 @@ void StealTargetItem(u8 battlerStealer, u8 itemBattler)
gLastUsedItem = gBattleMons[itemBattler].item;
gBattleMons[itemBattler].item = ITEM_NONE;
if (GetConfig(CONFIG_STEAL_WILD_ITEMS) >= GEN_9
if (GetConfig(B_STEAL_WILD_ITEMS) >= GEN_9
&& !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_PALACE))
&& GetMoveEffect(gCurrentMove) == EFFECT_STEAL_ITEM
&& battlerStealer == gBattlerAttacker) // ensure that Pickpocket isn't activating this
@ -3094,7 +3094,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
case MOVE_EFFECT_PARALYSIS:
case MOVE_EFFECT_TOXIC:
case MOVE_EFFECT_FROSTBITE:
if (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !primary)
if (IsSafeguardProtected(gBattlerAttacker, gEffectBattler, GetBattlerAbility(gBattlerAttacker)) && !primary)
gBattlescriptCurrInstr = battleScript;
else if (CanSetNonVolatileStatus(
gBattlerAttacker,
@ -3108,7 +3108,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
case MOVE_EFFECT_CONFUSION:
if (!CanBeConfused(gEffectBattler)
|| gBattleMons[gEffectBattler].volatiles.confusionTurns
|| (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !primary))
|| (IsSafeguardProtected(gBattlerAttacker, gEffectBattler, GetBattlerAbility(gBattlerAttacker)) && !primary))
{
gBattlescriptCurrInstr = battleScript;
}
@ -3236,9 +3236,9 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
else
{
if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_GRIP_CLAW)
gDisableStructs[gEffectBattler].wrapTurns = GetConfig(CONFIG_BINDING_TURNS) >= GEN_5 ? 7 : 5;
gDisableStructs[gEffectBattler].wrapTurns = GetConfig(B_BINDING_TURNS) >= GEN_5 ? 7 : 5;
else
gDisableStructs[gEffectBattler].wrapTurns = GetConfig(CONFIG_BINDING_TURNS) >= GEN_5 ? RandomUniform(RNG_WRAP, 4, 5) : RandomUniform(RNG_WRAP, 2, 5);
gDisableStructs[gEffectBattler].wrapTurns = GetConfig(B_BINDING_TURNS) >= GEN_5 ? RandomUniform(RNG_WRAP, 4, 5) : RandomUniform(RNG_WRAP, 2, 5);
gBattleMons[gEffectBattler].volatiles.wrapped = TRUE;
gBattleMons[gEffectBattler].volatiles.wrappedMove = gCurrentMove;
gBattleMons[gEffectBattler].volatiles.wrappedBy = gBattlerAttacker;
@ -3497,8 +3497,9 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
gBattlescriptCurrInstr = battleScript;
break;
case MOVE_EFFECT_INCINERATE:
if ((gBattleMons[gEffectBattler].item >= FIRST_BERRY_INDEX && gBattleMons[gEffectBattler].item <= LAST_BERRY_INDEX)
if (((gBattleMons[gEffectBattler].item >= FIRST_BERRY_INDEX && gBattleMons[gEffectBattler].item <= LAST_BERRY_INDEX)
|| (B_INCINERATE_GEMS >= GEN_6 && GetBattlerHoldEffect(gEffectBattler) == HOLD_EFFECT_GEMS))
&& battlerAbility != ABILITY_STICKY_HOLD)
{
gLastUsedItem = gBattleMons[gEffectBattler].item;
gBattleMons[gEffectBattler].item = 0;
@ -3998,7 +3999,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
{
gBattleMons[battler].volatiles.wrapped = TRUE;
if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_GRIP_CLAW)
gDisableStructs[battler].wrapTurns = (GetConfig(CONFIG_BINDING_TURNS) >= GEN_5) ? 7 : 5;
gDisableStructs[battler].wrapTurns = (GetConfig(B_BINDING_TURNS) >= GEN_5) ? 7 : 5;
else
gDisableStructs[battler].wrapTurns = (Random() % 2) + 4;
// The Wrap effect does not expire when the user switches, so here's some cheese.
@ -5417,7 +5418,7 @@ static void Cmd_isdmgblockedbydisguise(void)
gBattleMons[gBattlerAttacker].species = SPECIES_MIMIKYU_BUSTED_TOTEM;
else
gBattleMons[gBattlerAttacker].species = SPECIES_MIMIKYU_BUSTED;
if (GetConfig(CONFIG_DISGUISE_HP_LOSS) >= GEN_8)
if (GetConfig(B_DISGUISE_HP_LOSS) >= GEN_8)
SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 8);
BattleScriptPush(BattleScript_MoveEnd);
gBattlescriptCurrInstr = BattleScript_TargetFormChange;
@ -5744,7 +5745,7 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move
if (GetBattlerPartyState(battlerAtk)->battleBondBoost)
break;
if (GetConfig(CONFIG_BATTLE_BOND) < GEN_9 && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_BATTLE_BOND)
if (GetConfig(B_BATTLE_BOND) < GEN_9 && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_BATTLE_BOND)
{
// TODO: Convert this to a proper FORM_CHANGE type.
gLastUsedAbility = abilityAtk;
@ -5866,7 +5867,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
{
StealTargetItem(gBattlerAttacker, gBattlerTarget); // Attacker steals target item
if (!(GetConfig(CONFIG_STEAL_WILD_ITEMS) >= GEN_9
if (!(GetConfig(B_STEAL_WILD_ITEMS) >= GEN_9
&& !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_PALACE))))
{
gBattleMons[gBattlerAttacker].item = ITEM_NONE; // Item assigned later on with thief (see MOVEEND_CHANGED_ITEMS)
@ -6019,7 +6020,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
&& !NoAliveMonsForEitherParty()
&& CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerAttacker)))
{
SET_STATCHANGER(STAT_ATK, GetConfig(CONFIG_FELL_STINGER_STAT_RAISE) >= GEN_7 ? 3 : 2, FALSE);
SET_STATCHANGER(STAT_ATK, GetConfig(B_FELL_STINGER_STAT_RAISE) >= GEN_7 ? 3 : 2, FALSE);
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_FellStingerRaisesStat;
@ -6240,7 +6241,7 @@ static void Cmd_moveend(void)
s32 healAmount = (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100);
healAmount = GetDrainedBigRootHp(gBattlerAttacker, healAmount);
effect = TRUE;
if ((moveEffect == EFFECT_DREAM_EATER && GetConfig(CONFIG_DREAM_EATER_LIQUID_OOZE) < GEN_5)
if ((moveEffect == EFFECT_DREAM_EATER && GetConfig(B_DREAM_EATER_LIQUID_OOZE) < GEN_5)
|| GetBattlerAbility(gBattlerTarget) != ABILITY_LIQUID_OOZE)
{
SetHealAmount(gBattlerAttacker, healAmount);
@ -6333,7 +6334,7 @@ static void Cmd_moveend(void)
for (i = 0; i < gBattlersCount; i++)
{
if ((gSpecialStatuses[i].berryReduced
|| (GetConfig(CONFIG_SYMBIOSIS_GEMS) >= GEN_7 && gSpecialStatuses[i].gemBoost))
|| (GetConfig(B_SYMBIOSIS_GEMS) >= GEN_7 && gSpecialStatuses[i].gemBoost))
&& TryTriggerSymbiosis(i, BATTLE_PARTNER(i)))
{
BestowItem(BATTLE_PARTNER(i), i);
@ -6848,7 +6849,9 @@ static void Cmd_moveend(void)
for (i = 0; i < gBattlersCount; i++)
{
if (IsBattlerTurnDamaged(i) && EmergencyExitCanBeTriggered(i))
if (!IsBattleMoveStatus(gCurrentMove)
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& EmergencyExitCanBeTriggered(i))
{
emergencyExitBattlers |= 1u << i;
numEmergencyExitBattlers++;
@ -7001,11 +7004,21 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++;
break;
case MOVEEND_PICKPOCKET:
{
u16 attackerItem = gBattleMons[gBattlerAttacker].item;
bool32 hasPendingStolenItem = FALSE;
if (attackerItem == ITEM_NONE
&& GetMoveEffect(gCurrentMove) == EFFECT_STEAL_ITEM
&& gBattleStruct->changedItems[gBattlerAttacker] != ITEM_NONE)
{
attackerItem = gBattleStruct->changedItems[gBattlerAttacker];
hasPendingStolenItem = TRUE;
}
if (IsBattlerAlive(gBattlerAttacker)
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & (1u << gBattlerPartyIndexes[gBattlerAttacker])) // But not knocked off
&& IsMoveMakingContact(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) // Pickpocket requires contact
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Obviously attack needs to have worked
&& attackerItem != ITEM_NONE // Attacker must have an item (including pending stolen item)
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & (1u << gBattlerPartyIndexes[gBattlerAttacker]))) // But not knocked off
{
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE); // Pickpocket activates for fastest mon without item
@ -7016,12 +7029,19 @@ static void Cmd_moveend(void)
if (battler != gBattlerAttacker // Cannot pickpocket yourself
&& GetBattlerAbility(battler) == ABILITY_PICKPOCKET // Target must have pickpocket ability
&& IsBattlerTurnDamaged(battler) // Target needs to have been damaged
&& IsMoveMakingContact(gBattlerAttacker, battler, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) // Pickpocket requires contact
&& !(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT) // Move needs to have affected this battler
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) // Subsitute unaffected
&& IsBattlerAlive(battler) // Battler must be alive to pickpocket
&& gBattleMons[battler].item == ITEM_NONE // Pickpocketer can't have an item already
&& CanStealItem(battler, gBattlerAttacker, gBattleMons[gBattlerAttacker].item)) // Cannot steal plates, mega stones, etc
&& CanStealItem(battler, gBattlerAttacker, attackerItem)) // Cannot steal plates, mega stones, etc
{
gBattlerTarget = gBattlerAbility = battler;
if (hasPendingStolenItem)
{
gBattleMons[gBattlerAttacker].item = attackerItem;
gBattleStruct->changedItems[gBattlerAttacker] = ITEM_NONE;
}
// Battle scripting is super brittle so we shall do the item exchange now (if possible)
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD)
StealTargetItem(gBattlerTarget, gBattlerAttacker); // Target takes attacker's item
@ -7035,6 +7055,7 @@ static void Cmd_moveend(void)
}
gBattleScripting.moveendState++;
break;
}
case MOVEEND_THIRD_MOVE_BLOCK:
switch (moveEffect)
{
@ -7983,7 +8004,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler)
// Starting from Gen8 - it heals only pokemon which can be healed.
// In Gen5-7 the effect activates anyways.
else if ((gBattleStruct->battlerState[battler].storedHealingWish)
&& (GetConfig(CONFIG_HEALING_WISH_SWITCH) < GEN_8
&& (GetConfig(B_HEALING_WISH_SWITCH) < GEN_8
|| gBattleMons[battler].hp != gBattleMons[battler].maxHP
|| gBattleMons[battler].status1 != 0))
{
@ -7992,7 +8013,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler)
gBattleStruct->battlerState[battler].storedHealingWish = FALSE;
}
else if ((gBattleStruct->battlerState[battler].storedLunarDance)
&& (GetConfig(CONFIG_HEALING_WISH_SWITCH) < GEN_8
&& (GetConfig(B_HEALING_WISH_SWITCH) < GEN_8
|| gBattleMons[battler].hp != gBattleMons[battler].maxHP
|| gBattleMons[battler].status1 != 0
|| gBattleMons[battler].pp[0] < CalculatePPWithBonus(gBattleMons[battler].moves[0], gBattleMons[battler].ppBonuses, 0)
@ -8848,7 +8869,7 @@ static bool32 TrySymbiosis(u32 battler, u32 itemId, bool32 moveEnd)
&& gBattleStruct->changedItems[battler] == ITEM_NONE
&& GetBattlerHoldEffect(battler) != HOLD_EFFECT_EJECT_BUTTON
&& GetBattlerHoldEffect(battler) != HOLD_EFFECT_EJECT_PACK
&& (GetConfig(CONFIG_SYMBIOSIS_GEMS) < GEN_7 || !(gSpecialStatuses[battler].gemBoost))
&& (GetConfig(B_SYMBIOSIS_GEMS) < GEN_7 || !(gSpecialStatuses[battler].gemBoost))
&& GetMoveEffect(gCurrentMove) != EFFECT_FLING //Fling and damage-reducing berries are handled separately.
&& !gSpecialStatuses[battler].berryReduced
&& TryTriggerSymbiosis(battler, BATTLE_PARTNER(battler)))
@ -9442,7 +9463,7 @@ static bool32 TryDefogClear(u32 battlerAtk, bool32 clear)
DEFOG_CLEAR(SIDE_STATUS_AURORA_VEIL, auroraVeilTimer, BattleScript_SideStatusWoreOffReturn, MOVE_AURORA_VEIL);
DEFOG_CLEAR(SIDE_STATUS_SAFEGUARD, safeguardTimer, BattleScript_SideStatusWoreOffReturn, MOVE_SAFEGUARD);
}
if (GetConfig(CONFIG_DEFOG_EFFECT_CLEARING) >= GEN_6)
if (GetConfig(B_DEFOG_EFFECT_CLEARING) >= GEN_6)
{
gBattlerAttacker = i; // For correct battle string. Ally's / Foe's
if (DefogClearHazards(saveBattler, i, clear))
@ -9457,7 +9478,7 @@ static bool32 TryDefogClear(u32 battlerAtk, bool32 clear)
}
return TRUE;
}
if (GetConfig(CONFIG_DEFOG_EFFECT_CLEARING) >= GEN_8 && (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY))
if (GetConfig(B_DEFOG_EFFECT_CLEARING) >= GEN_8 && (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY))
{
if (clear)
{
@ -9561,7 +9582,7 @@ static bool32 IsElectricAbilityAffected(u32 battler, enum Ability ability)
moveType = GetMoveType(gCurrentMove);
if (moveType == TYPE_ELECTRIC
&& (ability != ABILITY_LIGHTNING_ROD || GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
&& (ability != ABILITY_LIGHTNING_ROD || GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5)
&& GetBattlerAbility(battler) == ability)
return TRUE;
else
@ -9691,7 +9712,7 @@ static bool32 ChangeOrderTargetAfterAttacker(void)
if (attackerTurnOrderNum > targetTurnOrderNum)
return FALSE;
if (attackerTurnOrderNum + 1 == targetTurnOrderNum)
return GetConfig(CONFIG_AFTER_YOU_TURN_ORDER) >= GEN_8;
return GetConfig(B_AFTER_YOU_TURN_ORDER) >= GEN_8;
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
@ -9734,8 +9755,8 @@ static void TryResetProtectUseCounter(u32 battler)
enum BattleMoveEffects lastEffect = GetMoveEffect(lastMove);
if (lastMove == MOVE_UNAVAILABLE
|| (!gBattleMoveEffects[lastEffect].usesProtectCounter
&& ((GetConfig(CONFIG_ALLY_SWITCH_FAIL_CHANCE) >= GEN_9 && lastEffect != EFFECT_ALLY_SWITCH)
|| GetConfig(CONFIG_ALLY_SWITCH_FAIL_CHANCE) < GEN_9)))
&& ((GetConfig(B_ALLY_SWITCH_FAIL_CHANCE) >= GEN_9 && lastEffect != EFFECT_ALLY_SWITCH)
|| GetConfig(B_ALLY_SWITCH_FAIL_CHANCE) < GEN_9)))
gDisableStructs[battler].protectUses = 0;
}
@ -9752,8 +9773,8 @@ static void Cmd_setprotectlike(void)
notLastTurn = FALSE;
if ((sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] >= RandomUniform(RNG_PROTECT_FAIL, 0, USHRT_MAX) && notLastTurn)
|| (protectMethod == PROTECT_WIDE_GUARD && GetConfig(CONFIG_WIDE_GUARD) >= GEN_6)
|| (protectMethod == PROTECT_QUICK_GUARD && GetConfig(CONFIG_QUICK_GUARD) >= GEN_6)
|| (protectMethod == PROTECT_WIDE_GUARD && GetConfig(B_WIDE_GUARD) >= GEN_6)
|| (protectMethod == PROTECT_QUICK_GUARD && GetConfig(B_QUICK_GUARD) >= GEN_6)
|| (protectMethod == PROTECT_CRAFTY_SHIELD))
{
if (GetMoveEffect(gCurrentMove) == EFFECT_ENDURE)
@ -10210,7 +10231,7 @@ static void TryPlayStatChangeAnimation(u32 battler, enum Ability ability, u32 st
}
}
else if (!((ability == ABILITY_KEEN_EYE || ability == ABILITY_MINDS_EYE) && currStat == STAT_ACC)
&& !(GetConfig(CONFIG_ILLUMINATE_EFFECT) >= GEN_9 && ability == ABILITY_ILLUMINATE && currStat == STAT_ACC)
&& !(GetConfig(B_ILLUMINATE_EFFECT) >= GEN_9 && ability == ABILITY_ILLUMINATE && currStat == STAT_ACC)
&& !(ability == ABILITY_HYPER_CUTTER && currStat == STAT_ATK)
&& !(ability == ABILITY_BIG_PECKS && currStat == STAT_DEF))
{
@ -10302,7 +10323,7 @@ static u32 ChangeStatBuffs(u32 battler, s8 statValue, enum Stat statId, union St
{
if (gSideTimers[GetBattlerSide(battler)].mistTimer
&& !flags.certain && gCurrentMove != MOVE_CURSE
&& !(battler == gBattlerTarget && GetBattlerAbility(gBattlerAttacker) == ABILITY_INFILTRATOR))
&& !(battler == gBattlerTarget && GetBattlerAbility(gBattlerAttacker) == ABILITY_INFILTRATOR && !IsBattlerAlly(gBattlerAttacker, battler)))
{
if (flags.allowPtr)
{
@ -10379,7 +10400,7 @@ static u32 ChangeStatBuffs(u32 battler, s8 statValue, enum Stat statId, union St
}
else if (!flags.certain
&& (((battlerAbility == ABILITY_KEEN_EYE || battlerAbility == ABILITY_MINDS_EYE) && statId == STAT_ACC)
|| (GetConfig(CONFIG_ILLUMINATE_EFFECT) >= GEN_9 && battlerAbility == ABILITY_ILLUMINATE && statId == STAT_ACC)
|| (GetConfig(B_ILLUMINATE_EFFECT) >= GEN_9 && battlerAbility == ABILITY_ILLUMINATE && statId == STAT_ACC)
|| (battlerAbility == ABILITY_HYPER_CUTTER && statId == STAT_ATK)
|| (battlerAbility == ABILITY_BIG_PECKS && statId == STAT_DEF)))
{
@ -11228,8 +11249,8 @@ static void Cmd_setfocusenergy(void)
}
else
{
if (GetConfig(CONFIG_FOCUS_ENERGY_CRIT_RATIO) >= GEN_3
|| GetConfig(CONFIG_CRIT_CHANCE) == GEN_1)
if (GetConfig(B_FOCUS_ENERGY_CRIT_RATIO) >= GEN_3
|| GetConfig(B_CRIT_CHANCE) == GEN_1)
gBattleMons[battler].volatiles.focusEnergy = TRUE;
else
gBattleMons[battler].volatiles.dragonCheer = TRUE;
@ -11245,6 +11266,7 @@ static void Cmd_transformdataexecution(void)
gChosenMove = MOVE_UNAVAILABLE;
gBattlescriptCurrInstr = cmd->nextInstr;
if (gBattleMons[gBattlerTarget].volatiles.transformed
|| DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)
|| gBattleStruct->illusion[gBattlerTarget].state == ILLUSION_ON
|| IsSemiInvulnerable(gBattlerTarget, EXCLUDE_COMMANDER))
{
@ -11565,7 +11587,7 @@ static void Cmd_settypetorandomresistance(void)
u32 moveToCheck;
u32 typeToCheck;
if (GetConfig(CONFIG_UPDATED_CONVERSION_2) < GEN_5)
if (GetConfig(B_UPDATED_CONVERSION_2) < GEN_5)
{
moveToCheck = gLastLandedMoves[gBattlerAttacker];
if (GetMoveEffect(moveToCheck) == EFFECT_STRUGGLE)
@ -11730,7 +11752,7 @@ static void Cmd_settailwind(void)
if (!(gSideStatuses[side] & SIDE_STATUS_TAILWIND))
{
gSideStatuses[side] |= SIDE_STATUS_TAILWIND;
gSideTimers[side].tailwindTimer = (GetConfig(CONFIG_TAILWIND_TURNS) >= GEN_5 ? 4 : 3);
gSideTimers[side].tailwindTimer = (GetConfig(B_TAILWIND_TURNS) >= GEN_5 ? 4 : 3);
gBattlescriptCurrInstr = cmd->nextInstr;
}
else
@ -11820,8 +11842,8 @@ static void Cmd_healpartystatus(void)
struct Pokemon *party = GetBattlerParty(gBattlerAttacker);
bool32 isSoundMove = IsSoundMove(gCurrentMove);
if (GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) == GEN_5
|| GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) >= GEN_8
if (GetConfig(B_HEAL_BELL_SOUNDPROOF) == GEN_5
|| GetConfig(B_HEAL_BELL_SOUNDPROOF) >= GEN_8
|| !(isSoundMove && GetBattlerAbility(gBattlerAttacker) == ABILITY_SOUNDPROOF))
{
if (isSoundMove)
@ -11841,7 +11863,7 @@ static void Cmd_healpartystatus(void)
if (IsBattlerAlive(partner))
{
if (GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) == GEN_5
if (GetConfig(B_HEAL_BELL_SOUNDPROOF) == GEN_5
|| !(isSoundMove && GetBattlerAbility(partner) == ABILITY_SOUNDPROOF))
{
gBattleMons[partner].status1 = 0;
@ -11867,10 +11889,10 @@ static void Cmd_healpartystatus(void)
bool32 isAttacker = gBattlerPartyIndexes[gBattlerAttacker] == i;
bool32 isDoublesPartner = gBattlerPartyIndexes[partner] == i && IsBattlerAlive(partner);
if (GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) == GEN_5
|| (GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) >= GEN_8 && isAttacker))
if (GetConfig(B_HEAL_BELL_SOUNDPROOF) == GEN_5
|| (GetConfig(B_HEAL_BELL_SOUNDPROOF) >= GEN_8 && isAttacker))
ability = ABILITY_NONE;
else if (GetConfig(CONFIG_HEAL_BELL_SOUNDPROOF) > GEN_5 && !isAttacker && !isDoublesPartner)
else if (GetConfig(B_HEAL_BELL_SOUNDPROOF) > GEN_5 && !isAttacker && !isDoublesPartner)
ability = ABILITY_NONE;
else if (isAttacker)
ability = GetBattlerAbility(gBattlerAttacker);
@ -12288,7 +12310,15 @@ static void Cmd_copyfoestats(void)
{
gBattleMons[gBattlerAttacker].statStages[i] = gBattleMons[gBattlerTarget].statStages[i];
}
gBattleScripting.battler = gBattlerTarget;
if (GetConfig(B_PSYCH_UP_CRIT_RATIO) >= GEN_6)
{
// Copy crit boosts (Focus Energy, Dragon Cheer, G-Max Chi Strike)
gBattleMons[gBattlerAttacker].volatiles.focusEnergy = gBattleMons[gBattlerTarget].volatiles.focusEnergy;
gBattleMons[gBattlerAttacker].volatiles.dragonCheer = gBattleMons[gBattlerTarget].volatiles.dragonCheer;
gBattleMons[gBattlerAttacker].volatiles.bonusCritStages = gBattleMons[gBattlerTarget].volatiles.bonusCritStages;
}
gEffectBattler = gBattlerTarget;
gBattleScripting.battler = gBattlerAttacker;
gBattlescriptCurrInstr = cmd->nextInstr;
}
@ -12350,7 +12380,7 @@ static void Cmd_recoverbasedonsunlight(void)
else
recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
}
else if (GetConfig(CONFIG_TIME_OF_DAY_HEALING_MOVES) != GEN_2)
else if (GetConfig(B_TIME_OF_DAY_HEALING_MOVES) != GEN_2)
{
if (!(gBattleWeather & B_WEATHER_ANY) || !HasWeatherEffect() || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA)
recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
@ -12638,7 +12668,7 @@ static void Cmd_settaunt(void)
{
CMD_ARGS(const u8 *failInstr);
if (GetConfig(CONFIG_OBLIVIOUS_TAUNT) >= GEN_6 && GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS)
if (GetConfig(B_OBLIVIOUS_TAUNT) >= GEN_6 && GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS)
{
gBattlescriptCurrInstr = BattleScript_NotAffectedAbilityPopUp;
gLastUsedAbility = ABILITY_OBLIVIOUS;
@ -13374,6 +13404,10 @@ bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move)
return FALSE;
else if (MoveIgnoresSubstitute(move))
return FALSE;
else if (GetConfig(B_INFILTRATOR_SUBSTITUTE) < GEN_6)
return TRUE;
else if (GetMoveEffect(move) == EFFECT_TRANSFORM || GetMoveEffect(move) == EFFECT_SKY_DROP)
return TRUE;
else if (IsAbilityAndRecord(battlerAtk, GetBattlerAbility(battlerAtk), ABILITY_INFILTRATOR))
return FALSE;
else
@ -14703,7 +14737,7 @@ bool32 CanBurnHitThaw(u16 move)
{
u8 i;
if (GetConfig(CONFIG_BURN_HIT_THAW) >= GEN_6)
if (GetConfig(B_BURN_HIT_THAW) >= GEN_6)
{
u32 numAdditionalEffects = GetMoveAdditionalEffectCount(move);
for (i = 0; i < numAdditionalEffects; i++)
@ -15487,7 +15521,7 @@ void BS_TryAllySwitch(void)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (GetConfig(CONFIG_ALLY_SWITCH_FAIL_CHANCE) >= GEN_9)
else if (GetConfig(B_ALLY_SWITCH_FAIL_CHANCE) >= GEN_9)
{
TryResetProtectUseCounter(gBattlerAttacker);
if (sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] < Random())
@ -16367,7 +16401,7 @@ void BS_JumpIfIntimidateAbilityPrevented(void)
case ABILITY_SCRAPPY:
case ABILITY_OWN_TEMPO:
case ABILITY_OBLIVIOUS:
if (GetConfig(CONFIG_UPDATED_INTIMIDATE) >= GEN_8)
if (GetConfig(B_UPDATED_INTIMIDATE) >= GEN_8)
{
hasAbility = TRUE;
gBattlescriptCurrInstr = BattleScript_IntimidatePrevented;
@ -17357,21 +17391,26 @@ void BS_TryInstruct(void)
gSpecialStatuses[gBattlerTarget].instructedChosenTarget = gBattleStruct->moveTarget[gBattlerTarget] | 0x4;
gCalledMove = move;
u32 moveIndex;
bool32 foundMove = FALSE;
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
{
if (gBattleMons[gBattlerTarget].moves[moveIndex] == gCalledMove)
{
gCurrMovePos = moveIndex;
moveIndex = MAX_MON_MOVES;
foundMove = TRUE;
break;
}
}
if (moveIndex != MAX_MON_MOVES || gBattleMons[gBattlerTarget].pp[gCurrMovePos] == 0)
if (!foundMove)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (gBattleMons[gBattlerTarget].pp[moveIndex] == 0)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else
{
gCurrMovePos = moveIndex;
gBattleScripting.battler = gBattlerAttacker; // for message
gEffectBattler = gBattleStruct->lastMoveTarget[gBattlerTarget];
gBattlescriptCurrInstr = cmd->nextInstr;
@ -17978,7 +18017,7 @@ void BS_JumpIfAbilityPreventsRest(void)
NATIVE_ARGS(u8 battler, const u8 *jumpInstr);
u32 battler = GetBattlerForBattleScript(cmd->battler);
u32 ability = GetBattlerAbility(battler);
if (GetConfig(CONFIG_LEAF_GUARD_PREVENTS_REST) >= GEN_5 && IsLeafGuardProtected(battler, ability))
if (GetConfig(B_LEAF_GUARD_PREVENTS_REST) >= GEN_5 && IsLeafGuardProtected(battler, ability))
gBattlescriptCurrInstr = cmd->jumpInstr;
else if (IsShieldsDownProtected(battler, ability))
gBattlescriptCurrInstr = cmd->jumpInstr;
@ -18073,7 +18112,7 @@ void BS_BattlerItemToLastUsedItem(void)
void BS_JumpIfGenConfigLowerThan(void)
{
NATIVE_ARGS(u16 tag, u8 gen, const u8 *jumpInstr);
if (GetConfig(cmd->tag) < cmd->gen)
if (GetConfigInternal(cmd->tag) < cmd->gen)
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;

View File

@ -940,6 +940,7 @@ static bool32 IsPlayerDefeated(u32 battleOutcome)
{
case B_OUTCOME_LOST:
case B_OUTCOME_DREW:
case B_OUTCOME_FORFEITED:
return TRUE;
case B_OUTCOME_WON:
case B_OUTCOME_RAN:

View File

@ -480,7 +480,7 @@ void HandleAction_UseMove(void)
{
gCurrentMove = gChosenMove = gDisableStructs[gBattlerAttacker].encoredMove;
gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos;
if (GetConfig(CONFIG_ENCORE_TARGET) < GEN_5)
if (GetConfig(B_ENCORE_TARGET) < GEN_5)
gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
}
// check if the encored move wasn't overwritten
@ -695,7 +695,7 @@ bool32 TryRunFromBattle(u32 battler)
gProtectStructs[battler].fleeType = FLEE_ITEM;
effect++;
}
else if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
else if (GetConfig(B_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
{
effect++;
}
@ -970,7 +970,7 @@ void HandleAction_ActionFinished(void)
gBattleResources->battleScriptsStack->size = 0;
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE;
if (GetConfig(CONFIG_RECALC_TURN_AFTER_ACTIONS) >= GEN_8 && !afterYouActive && !gBattleStruct->pledgeMove && !IsPursuitTargetSet())
if (GetConfig(B_RECALC_TURN_AFTER_ACTIONS) >= GEN_8 && !afterYouActive && !gBattleStruct->pledgeMove && !IsPursuitTargetSet())
{
// i starts at `gCurrentTurnActionNumber` because we don't want to recalculate turn order for mon that have already
// taken action. It's been previously increased, which we want in order to not recalculate the turn of the mon that just finished its action
@ -1245,7 +1245,7 @@ bool32 ShouldDefiantCompetitiveActivate(u32 battler, enum Ability ability)
if (IsBattlerAlly(gSpecialStatuses[battler].changedStatsBattlerId, battler) && !gBattleScripting.stickyWebStatDrop)
return FALSE;
if (GetConfig(CONFIG_DEFIANT_STICKY_WEB) >= GEN_9 || !gBattleScripting.stickyWebStatDrop)
if (GetConfig(B_DEFIANT_STICKY_WEB) >= GEN_9 || !gBattleScripting.stickyWebStatDrop)
return TRUE;
// only activate Defiant/Competitive if Web was setup by foe
return gSideTimers[side].stickyWebBattlerSide != side;
@ -1283,7 +1283,7 @@ void PrepareStringBattle(enum StringID stringId, u32 battler)
stringId = STRINGID_STATSWONTINCREASE2;
break;
case STRINGID_PKMNCUTSATTACKWITH:
if (GetConfig(CONFIG_UPDATED_INTIMIDATE) >= GEN_8
if (GetConfig(B_UPDATED_INTIMIDATE) >= GEN_8
&& targetAbility == ABILITY_RATTLED
&& CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, targetAbility))
{
@ -1425,7 +1425,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler)
u16 *choicedMove = &gBattleStruct->choicedMove[battler];
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
if (GetConfig(CONFIG_ENCORE_TARGET) >= GEN_5
if (GetConfig(B_ENCORE_TARGET) >= GEN_5
&& DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].encoredMove != move && gDisableStructs[battler].encoredMove != MOVE_NONE)
{
gBattleScripting.battler = battler;
@ -2282,7 +2282,7 @@ static enum MoveCanceler CancelerConfused(struct BattleContext *ctx)
if (gBattleMons[ctx->battlerAtk].volatiles.confusionTurns)
{
// confusion dmg
if (RandomPercentage(RNG_CONFUSION, (GetConfig(CONFIG_CONFUSION_SELF_DMG_CHANCE) >= GEN_7 ? 33 : 50)))
if (RandomPercentage(RNG_CONFUSION, (GetConfig(B_CONFUSION_SELF_DMG_CHANCE) >= GEN_7 ? 33 : 50)))
{
gBattleCommunication[MULTISTRING_CHOOSER] = TRUE;
struct DamageContext dmgCtx = {0};
@ -2619,7 +2619,7 @@ static enum MoveCanceler CancelerWeatherPrimal(struct BattleContext *ctx)
if (HasWeatherEffect() && GetMovePower(ctx->currentMove) > 0)
{
enum Type moveType = GetBattleMoveType(ctx->currentMove);
if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && (GetConfig(CONFIG_POWDER_RAIN) >= GEN_7 || !TryActivatePowderStatus(ctx->currentMove)))
if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && (GetConfig(B_POWDER_RAIN) >= GEN_7 || !TryActivatePowderStatus(ctx->currentMove)))
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_FIZZLED_BY_RAIN;
effect = MOVE_STEP_FAILURE;
@ -2852,7 +2852,7 @@ static enum MoveCanceler CancelerProtean(struct BattleContext *ctx)
enum Type moveType = GetBattleMoveType(ctx->currentMove);
if (ProteanTryChangeType(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ctx->currentMove, moveType))
{
if (GetConfig(CONFIG_PROTEAN_LIBERO) >= GEN_9)
if (GetConfig(B_PROTEAN_LIBERO) >= GEN_9)
gDisableStructs[ctx->battlerAtk].usedProteanLibero = TRUE;
PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType);
gBattlerAbility = ctx->battlerAtk;
@ -2935,7 +2935,7 @@ static enum MoveCanceler CancelerMultihitMoves(struct BattleContext *ctx)
&& !GetMonData(&party[i], MON_DATA_IS_EGG)
&& !GetMonData(&party[i], MON_DATA_STATUS))
{
if (GetConfig(CONFIG_BEAT_UP) >= GEN_5)
if (GetConfig(B_BEAT_UP) >= GEN_5)
gBattleStruct->beatUpSpecies[gMultiHitCounter] = species;
else
gBattleStruct->beatUpSpecies[gMultiHitCounter] = i;
@ -3232,7 +3232,7 @@ bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, u32 ability)
{
return FALSE;
}
else if (GetConfig(CONFIG_ABILITY_WEATHER) < GEN_6 && ability != ABILITY_NONE)
else if (GetConfig(B_ABILITY_WEATHER) < GEN_6 && ability != ABILITY_NONE)
{
gBattleWeather = sBattleWeatherInfo[battleWeatherId].flag;
for (u32 i = 0; i < gBattlersCount; i++)
@ -3335,12 +3335,43 @@ static void ForewarnChooseMove(u32 battler)
}
}
for (bestId = 0, i = 1; i < count; i++)
if (count == 0)
{
if (data[i].power > data[bestId].power)
Free(data);
return;
}
u32 tieCount = 1;
u8 bestPower = data[0].power;
bestId = 0;
for (i = 1; i < count; i++)
{
if (data[i].power > bestPower)
{
bestPower = data[i].power;
bestId = i;
else if (data[i].power == data[bestId].power && Random() & 1)
tieCount = 1;
}
else if (data[i].power == bestPower)
{
tieCount++;
}
}
if (tieCount > 1)
{
u32 tieIndex = RandomUniform(RNG_FOREWARN, 0, tieCount - 1);
for (i = 0, bestId = 0; i < count; i++)
{
if (data[i].power != bestPower)
continue;
if (tieIndex-- == 0)
{
bestId = i;
break;
}
}
}
gEffectBattler = data[bestId].battler;
@ -3551,14 +3582,14 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability ability
}
break;
case ABILITY_LIGHTNING_ROD:
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && moveType == TYPE_ELECTRIC && GetBattlerMoveTargetType(battlerAtk, move) != MOVE_TARGET_ALL_BATTLERS)
if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && moveType == TYPE_ELECTRIC && GetBattlerMoveTargetType(battlerAtk, move) != MOVE_TARGET_ALL_BATTLERS)
{
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
statId = STAT_SPATK;
}
break;
case ABILITY_STORM_DRAIN:
if (GetConfig(CONFIG_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && moveType == TYPE_WATER)
if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && moveType == TYPE_WATER)
{
effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY;
statId = STAT_SPATK;
@ -4155,7 +4186,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
return effect; // Note: It returns effect as to not record the ability if Frisk does not activate.
case ABILITY_FOREWARN:
if (!gSpecialStatuses[battler].switchInAbilityDone)
if (!gSpecialStatuses[battler].switchInAbilityDone && !IsOpposingSideEmpty(battler))
{
ForewarnChooseMove(battler);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_FOREWARN;
@ -4298,12 +4329,12 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
break;
case ABILITY_SNOW_WARNING:
if (GetConfig(CONFIG_SNOW_WARNING) >= GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_SNOW, gLastUsedAbility))
if (GetConfig(B_SNOW_WARNING) >= GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_SNOW, gLastUsedAbility))
{
BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivatesSnow);
effect++;
}
else if (GetConfig(CONFIG_SNOW_WARNING) < GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_HAIL, gLastUsedAbility))
else if (GetConfig(B_SNOW_WARNING) < GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_HAIL, gLastUsedAbility))
{
BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivatesHail);
effect++;
@ -4402,7 +4433,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (!gSpecialStatuses[battler].switchInAbilityDone
&& !GetBattlerPartyState(battler)->intrepidSwordBoost)
{
if (GetConfig(CONFIG_INTREPID_SWORD) == GEN_9)
if (GetConfig(B_INTREPID_SWORD) == GEN_9)
GetBattlerPartyState(battler)->intrepidSwordBoost = TRUE;
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
if (CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
@ -4417,7 +4448,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (!gSpecialStatuses[battler].switchInAbilityDone
&& !GetBattlerPartyState(battler)->dauntlessShieldBoost)
{
if (GetConfig(CONFIG_DAUNTLESS_SHIELD) == GEN_9)
if (GetConfig(B_DAUNTLESS_SHIELD) == GEN_9)
GetBattlerPartyState(battler)->dauntlessShieldBoost = TRUE;
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
if (CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility))
@ -4602,6 +4633,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
&& IsBattlerAlive(battler)
&& gBattleStruct->battlerState[partner].commanderSpecies == SPECIES_NONE
&& gBattleMons[partner].species == SPECIES_DONDOZO
&& (gChosenActionByBattler[partner] != B_ACTION_SWITCH || HasBattlerActedThisTurn(partner))
&& GET_BASE_SPECIES_ID(GetMonData(GetBattlerMon(battler), MON_DATA_SPECIES)) == SPECIES_TATSUGIRI)
{
SaveBattlerAttacker(gBattlerAttacker);
@ -4686,7 +4718,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
break;
case ABILITY_SHED_SKIN:
if ((gBattleMons[battler].status1 & STATUS1_ANY)
&& (GetConfig(CONFIG_ABILITY_TRIGGER_CHANCE) == GEN_4 ? RandomPercentage(RNG_SHED_SKIN, 30) : RandomChance(RNG_SHED_SKIN, 1, 3)))
&& (GetConfig(B_ABILITY_TRIGGER_CHANCE) == GEN_4 ? RandomPercentage(RNG_SHED_SKIN, 30) : RandomChance(RNG_SHED_SKIN, 1, 3)))
{
ABILITY_HEAL_MON_STATUS:
if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON))
@ -4727,7 +4759,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (gDisableStructs[battler].isFirstTurn != 2)
{
u32 validToRaise = 0, validToLower = 0;
u32 statsNum = GetConfig(CONFIG_MOODY_ACC_EVASION) >= GEN_8 ? NUM_STATS : NUM_BATTLE_STATS;
u32 statsNum = GetConfig(B_MOODY_ACC_EVASION) >= GEN_8 ? NUM_STATS : NUM_BATTLE_STATS;
for (i = STAT_ATK; i < statsNum; i++)
{
@ -5110,7 +5142,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
{
u32 poison, paralysis, sleep;
if (GetConfig(CONFIG_ABILITY_TRIGGER_CHANCE) >= GEN_5)
if (GetConfig(B_ABILITY_TRIGGER_CHANCE) >= GEN_5)
{
poison = 9;
paralysis = 19;
@ -5122,7 +5154,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
sleep = 30;
i = RandomUniform(RNG_EFFECT_SPORE, 0, GetConfig(CONFIG_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? 99 : 299);
i = RandomUniform(RNG_EFFECT_SPORE, 0, GetConfig(B_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? 99 : 299);
if (i < poison)
goto POISON_POINT;
if (i < paralysis)
@ -5148,7 +5180,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
break;
case ABILITY_POISON_POINT:
if (GetConfig(CONFIG_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? RandomPercentage(RNG_POISON_POINT, 30) : RandomChance(RNG_POISON_POINT, 1, 3))
if (GetConfig(B_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? RandomPercentage(RNG_POISON_POINT, 30) : RandomChance(RNG_POISON_POINT, 1, 3))
{
POISON_POINT:
{
@ -5170,7 +5202,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
break;
case ABILITY_STATIC:
if (GetConfig(CONFIG_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? RandomPercentage(RNG_STATIC, 30) : RandomChance(RNG_STATIC, 1, 3))
if (GetConfig(B_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? RandomPercentage(RNG_STATIC, 30) : RandomChance(RNG_STATIC, 1, 3))
{
STATIC:
{
@ -5197,7 +5229,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
&& !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)
&& IsBattlerTurnDamaged(gBattlerTarget)
&& CanBeBurned(gBattlerTarget, gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))
&& (GetConfig(CONFIG_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? RandomPercentage(RNG_FLAME_BODY, 30) : RandomChance(RNG_FLAME_BODY, 1, 3)))
&& (GetConfig(B_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? RandomPercentage(RNG_FLAME_BODY, 30) : RandomChance(RNG_FLAME_BODY, 1, 3)))
{
gEffectBattler = gBattlerAttacker;
gBattleScripting.battler = gBattlerTarget;
@ -5212,7 +5244,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(gBattlerTarget)
&& (GetConfig(CONFIG_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? RandomPercentage(RNG_CUTE_CHARM, 30) : RandomChance(RNG_CUTE_CHARM, 1, 3))
&& (GetConfig(B_ABILITY_TRIGGER_CHANCE) >= GEN_4 ? RandomPercentage(RNG_CUTE_CHARM, 30) : RandomChance(RNG_CUTE_CHARM, 1, 3))
&& !(gBattleMons[gBattlerAttacker].volatiles.infatuation)
&& AreBattlersOfOppositeGender(gBattlerAttacker, gBattlerTarget)
&& !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_OBLIVIOUS)
@ -5500,7 +5532,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
gBattleScripting.battler = gBattlerAbility = gBattlerTarget;
RecordAbilityBattle(gBattlerTarget, ABILITY_SYNCHRONIZE);
if (GetConfig(CONFIG_SYNCHRONIZE_TOXIC) < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
if (GetConfig(B_SYNCHRONIZE_TOXIC) < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
if (CanSetNonVolatileStatus(
@ -5530,7 +5562,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
gBattleScripting.battler = gBattlerAbility = gBattlerAttacker;
RecordAbilityBattle(gBattlerAttacker, ABILITY_SYNCHRONIZE);
if (GetConfig(CONFIG_SYNCHRONIZE_TOXIC) < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
if (GetConfig(B_SYNCHRONIZE_TOXIC) < GEN_5 && gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
if (CanSetNonVolatileStatus(
@ -5804,7 +5836,7 @@ u32 IsAbilityOnFieldExcept(u32 battler, enum Ability ability)
u32 IsAbilityPreventingEscape(u32 battler)
{
if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
if (GetConfig(B_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
return 0;
bool32 isBattlerGrounded = IsBattlerGrounded(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler));
@ -5832,7 +5864,7 @@ bool32 CanBattlerEscape(u32 battler) // no ability check
{
if (gBattleStruct->battlerState[battler].commanderSpecies != SPECIES_NONE)
return FALSE;
else if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
else if (GetConfig(B_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
return TRUE;
else if (gBattleMons[battler].volatiles.escapePrevention)
return FALSE;
@ -6082,6 +6114,17 @@ bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef)
return FALSE;
}
bool32 IsSafeguardProtected(u32 battlerAtk, u32 battlerDef, u32 abilityAtk)
{
if (!(gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD))
return FALSE;
if (IsBattlerAlly(battlerAtk, battlerDef))
return TRUE;
if (abilityAtk == ABILITY_INFILTRATOR)
return FALSE;
return TRUE;
}
bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum MoveEffect effect, enum FunctionCallOption option)
{
const u8 *battleScript = NULL;
@ -6119,7 +6162,7 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abil
{
battleScript = BattleScript_AlreadyParalyzed;
}
else if (GetConfig(CONFIG_PARALYZE_ELECTRIC) >= GEN_6 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC))
else if (GetConfig(B_PARALYZE_ELECTRIC) >= GEN_6 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC))
{
battleScript = BattleScript_NotAffected;
}
@ -6236,7 +6279,7 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abil
abilityDef = ABILITY_FLOWER_VEIL;
battleScript = BattleScript_FlowerVeilProtects;
}
else if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD)
else if (IsSafeguardProtected(battlerAtk, battlerDef, abilityAtk))
{
battleScript = BattleScript_SafeguardProtected;
}
@ -7264,7 +7307,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx)
basePower *= 2;
break;
case EFFECT_BEAT_UP:
if (GetConfig(CONFIG_BEAT_UP) >= GEN_5)
if (GetConfig(B_BEAT_UP) >= GEN_5)
basePower = CalcBeatUpPower();
break;
case EFFECT_PSYBLADE:
@ -7378,9 +7421,9 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx)
if (IsBattlerTerrainAffected(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk, STATUS_FIELD_PSYCHIC_TERRAIN) && moveType == TYPE_PSYCHIC)
modifier = uq4_12_multiply(modifier, (B_TERRAIN_TYPE_BOOST >= GEN_8 ? UQ_4_12(1.3) : UQ_4_12(1.5)));
if (IsFieldMudSportAffected(ctx->moveType))
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(CONFIG_SPORT_DMG_REDUCTION) >= GEN_5 ? 0.33 : 0.5));
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(B_SPORT_DMG_REDUCTION) >= GEN_5 ? 0.33 : 0.5));
if (IsFieldWaterSportAffected(ctx->moveType))
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(CONFIG_SPORT_DMG_REDUCTION) >= GEN_5 ? 0.33 : 0.5));
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(B_SPORT_DMG_REDUCTION) >= GEN_5 ? 0.33 : 0.5));
// attacker's abilities
switch (ctx->abilityAtk)
@ -7446,22 +7489,22 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx)
break;
case ABILITY_PIXILATE:
if (moveType == TYPE_FAIRY && gBattleStruct->battlerState[battlerAtk].ateBoost)
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(CONFIG_ATE_MULTIPLIER) >= GEN_7 ? 1.2 : 1.3));
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(B_ATE_MULTIPLIER) >= GEN_7 ? 1.2 : 1.3));
break;
case ABILITY_GALVANIZE:
if (moveType == TYPE_ELECTRIC && gBattleStruct->battlerState[battlerAtk].ateBoost)
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(CONFIG_ATE_MULTIPLIER) >= GEN_7 ? 1.2 : 1.3));
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(B_ATE_MULTIPLIER) >= GEN_7 ? 1.2 : 1.3));
break;
case ABILITY_REFRIGERATE:
if (moveType == TYPE_ICE && gBattleStruct->battlerState[battlerAtk].ateBoost)
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(CONFIG_ATE_MULTIPLIER) >= GEN_7 ? 1.2 : 1.3));
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(B_ATE_MULTIPLIER) >= GEN_7 ? 1.2 : 1.3));
break;
case ABILITY_AERILATE:
if (moveType == TYPE_FLYING && gBattleStruct->battlerState[battlerAtk].ateBoost)
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(CONFIG_ATE_MULTIPLIER) >= GEN_7 ? 1.2 : 1.3));
modifier = uq4_12_multiply(modifier, UQ_4_12(GetConfig(B_ATE_MULTIPLIER) >= GEN_7 ? 1.2 : 1.3));
break;
case ABILITY_NORMALIZE:
if (moveType == TYPE_NORMAL && gBattleStruct->battlerState[battlerAtk].ateBoost && GetConfig(CONFIG_ATE_MULTIPLIER) >= GEN_7)
if (moveType == TYPE_NORMAL && gBattleStruct->battlerState[battlerAtk].ateBoost && GetConfig(B_ATE_MULTIPLIER) >= GEN_7)
modifier = uq4_12_multiply(modifier, UQ_4_12(1.2));
break;
case ABILITY_PUNK_ROCK:
@ -7793,7 +7836,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx)
case ABILITY_TRANSISTOR:
if (moveType == TYPE_ELECTRIC)
{
if (GetConfig(CONFIG_TRANSISTOR_BOOST) >= GEN_9)
if (GetConfig(B_TRANSISTOR_BOOST) >= GEN_9)
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
else
modifier = uq4_12_multiply(modifier, UQ_4_12(1.5));
@ -7902,7 +7945,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx)
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0));
break;
case HOLD_EFFECT_LIGHT_BALL:
if (atkBaseSpeciesId == SPECIES_PIKACHU && (GetConfig(CONFIG_LIGHT_BALL_ATTACK_BOOST) >= GEN_4 || IsBattleMoveSpecial(move)))
if (atkBaseSpeciesId == SPECIES_PIKACHU && (GetConfig(B_LIGHT_BALL_ATTACK_BOOST) >= GEN_4 || IsBattleMoveSpecial(move)))
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0));
break;
case HOLD_EFFECT_CHOICE_BAND:
@ -8110,7 +8153,7 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx)
}
// sandstorm sp.def boost for rock types
if (GetConfig(CONFIG_SANDSTORM_SPDEF_BOOST) >= GEN_4 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ROCK) && IsBattlerWeatherAffected(battlerDef, B_WEATHER_SANDSTORM) && !usesDefStat)
if (GetConfig(B_SANDSTORM_SPDEF_BOOST) >= GEN_4 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ROCK) && IsBattlerWeatherAffected(battlerDef, B_WEATHER_SANDSTORM) && !usesDefStat)
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
// snow def boost for ice types
if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE) && IsBattlerWeatherAffected(battlerDef, B_WEATHER_SNOW) && usesDefStat)
@ -8188,12 +8231,12 @@ static inline uq4_12_t GetBurnOrFrostBiteModifier(struct DamageContext *ctx)
if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_BURN
&& IsBattleMovePhysical(ctx->move)
&& (GetConfig(CONFIG_BURN_FACADE_DMG) < GEN_6 || moveEffect != EFFECT_FACADE)
&& (GetConfig(B_BURN_FACADE_DMG) < GEN_6 || moveEffect != EFFECT_FACADE)
&& ctx->abilityAtk != ABILITY_GUTS)
return UQ_4_12(0.5);
if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_FROSTBITE
&& IsBattleMoveSpecial(ctx->move)
&& (GetConfig(CONFIG_BURN_FACADE_DMG) < GEN_6 || moveEffect != EFFECT_FACADE))
&& (GetConfig(B_BURN_FACADE_DMG) < GEN_6 || moveEffect != EFFECT_FACADE))
return UQ_4_12(0.5);
return UQ_4_12(1.0);
}
@ -8201,7 +8244,7 @@ static inline uq4_12_t GetBurnOrFrostBiteModifier(struct DamageContext *ctx)
static inline uq4_12_t GetCriticalModifier(bool32 isCrit)
{
if (isCrit)
return GetConfig(CONFIG_CRIT_MULTIPLIER) >= GEN_6 ? UQ_4_12(1.5) : UQ_4_12(2.0);
return GetConfig(B_CRIT_MULTIPLIER) >= GEN_6 ? UQ_4_12(1.5) : UQ_4_12(2.0);
return UQ_4_12(1.0);
}
@ -8262,7 +8305,7 @@ static inline uq4_12_t GetScreensModifier(struct DamageContext *ctx)
{
return UQ_4_12(1.0);
}
if (ctx->abilityAtk == ABILITY_INFILTRATOR)
if (ctx->abilityAtk == ABILITY_INFILTRATOR && !IsBattlerAlly(ctx->battlerAtk, ctx->battlerDef))
{
if (ctx->updateFlags)
RecordAbilityBattle(ctx->battlerAtk, ctx->abilityDef);
@ -8566,7 +8609,7 @@ s32 DoFixedDamageMoveCalc(struct DamageContext *ctx)
dmg = GetNonDynamaxHP(ctx->battlerAtk);
break;
case EFFECT_BEAT_UP:
if (GetConfig(CONFIG_BEAT_UP) < GEN_5)
if (GetConfig(B_BEAT_UP) < GEN_5)
dmg = CalcBeatUpDamage(ctx);
else
return INT32_MAX;
@ -8840,7 +8883,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont
RecordAbilityBattle(ctx->battlerDef, ABILITY_LEVITATE);
}
}
else if (GetConfig(CONFIG_SHEER_COLD_IMMUNITY) >= GEN_7 && GetMoveEffect(ctx->move) == EFFECT_SHEER_COLD && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_ICE))
else if (GetConfig(B_SHEER_COLD_IMMUNITY) >= GEN_7 && GetMoveEffect(ctx->move) == EFFECT_SHEER_COLD && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_ICE))
{
modifier = UQ_4_12(0.0);
}
@ -8854,7 +8897,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont
}
// Iron Ball ignores type modifiers for flying-type mons if it is the only source of grounding
if (GetConfig(CONFIG_IRON_BALL) >= GEN_5
if (GetConfig(B_IRON_BALL) >= GEN_5
&& ctx->moveType == TYPE_GROUND
&& ctx->holdEffectDef == HOLD_EFFECT_IRON_BALL
&& IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_FLYING)
@ -9409,20 +9452,24 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method)
bool32 DoBattlersShareType(u32 battler1, u32 battler2)
{
s32 i;
s32 j;
enum Type types1[3], types2[3];
GetBattlerTypes(battler1, FALSE, types1);
GetBattlerTypes(battler2, FALSE, types2);
if (types1[2] == TYPE_MYSTERY)
types1[2] = types1[0];
if (types2[2] == TYPE_MYSTERY)
types2[2] = types2[0];
for (i = 0; i < 3; i++)
{
if (types1[i] == types2[0] || types1[i] == types2[1] || types1[i] == types2[2])
if (types1[i] == TYPE_MYSTERY)
continue;
for (j = 0; j < 3; j++)
{
if (types2[j] == TYPE_MYSTERY)
continue;
if (types1[i] == types2[j])
return TRUE;
}
}
return FALSE;
}
@ -9616,7 +9663,7 @@ u32 TryImmunityAbilityHealStatus(u32 battler, enum AbilityEffect caseID)
case ABILITY_OBLIVIOUS:
if (gBattleMons[battler].volatiles.infatuation)
effect = 3;
else if (GetConfig(CONFIG_OBLIVIOUS_TAUNT) >= GEN_6 && gDisableStructs[battler].tauntTimer != 0)
else if (GetConfig(B_OBLIVIOUS_TAUNT) >= GEN_6 && gDisableStructs[battler].tauntTimer != 0)
effect = 4;
break;
}
@ -9666,7 +9713,7 @@ u32 TryImmunityAbilityHealStatus(u32 battler, enum AbilityEffect caseID)
uq4_12_t GetBadgeBoostModifier(void)
{
if (GetConfig(CONFIG_BADGE_BOOST) < GEN_3)
if (GetConfig(B_BADGE_BOOST) < GEN_3)
return UQ_4_12(1.125);
else
return UQ_4_12(1.1);
@ -9674,7 +9721,7 @@ uq4_12_t GetBadgeBoostModifier(void)
bool32 ShouldGetStatBadgeBoost(u16 badgeFlag, u32 battler)
{
if (GetConfig(CONFIG_BADGE_BOOST) <= GEN_3 && badgeFlag != 0)
if (GetConfig(B_BADGE_BOOST) <= GEN_3 && badgeFlag != 0)
{
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_FRONTIER))
return FALSE;
@ -9802,9 +9849,10 @@ bool32 CanFling(u32 battler)
u16 item = gBattleMons[battler].item;
if (item == ITEM_NONE
|| (GetConfig(CONFIG_KLUTZ_FLING_INTERACTION) >= GEN_5 && GetBattlerAbility(battler) == ABILITY_KLUTZ)
|| (GetConfig(B_KLUTZ_FLING_INTERACTION) >= GEN_5 && GetBattlerAbility(battler) == ABILITY_KLUTZ)
|| gFieldStatuses & STATUS_FIELD_MAGIC_ROOM
|| gBattleMons[battler].volatiles.embargo
|| (GetItemTMHMIndex(item) != 0 && GetItemImportance(item) == 1) // don't fling reusable TMs
|| GetFlingPowerFromItemId(item) == 0
|| !CanBattlerGetOrLoseItem(battler, item))
return FALSE;
@ -10010,7 +10058,7 @@ bool32 CompareStat(u32 battler, enum Stat statId, u8 cmpTo, u8 cmpKind, enum Abi
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget)
{
if (GetConfig(CONFIG_PRANKSTER_DARK_TYPES) < GEN_7)
if (GetConfig(B_PRANKSTER_DARK_TYPES) < GEN_7)
return FALSE;
if (!gProtectStructs[battlerPrankster].pranksterElevated)
return FALSE;
@ -10029,7 +10077,7 @@ bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 ch
bool32 CantPickupItem(u32 battler)
{
// Used by RandomUniformExcept() for RNG_PICKUP
if (battler == gBattlerAttacker && (GetConfig(CONFIG_PICKUP_WILD) < GEN_9 || gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK)))
if (battler == gBattlerAttacker && (GetConfig(B_PICKUP_WILD) < GEN_9 || gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK)))
return TRUE;
return !(IsBattlerAlive(battler) && GetBattlerPartyState(battler)->usedHeldItem && gBattleStruct->battlerState[battler].canPickupItem);
}
@ -10091,7 +10139,7 @@ static void SetRandomMultiHitCounter()
{
if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_LOADED_DICE)
gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 5);
else if (GetConfig(CONFIG_MULTI_HIT_CHANCE) >= GEN_5)
else if (GetConfig(B_MULTI_HIT_CHANCE) >= GEN_5)
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 7, 7, 3, 3); // 35%: 2 hits, 35%: 3 hits, 15% 4 hits, 15% 5 hits.
else
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 3, 3, 1, 1); // 37.5%: 2 hits, 37.5%: 3 hits, 12.5% 4 hits, 12.5% 5 hits.
@ -10529,7 +10577,7 @@ void ClearDamageCalcResults(void)
bool32 DoesDestinyBondFail(u32 battler)
{
return GetConfig(CONFIG_DESTINY_BOND_FAIL) >= GEN_7 && gBattleMons[battler].volatiles.destinyBond;
return GetConfig(B_DESTINY_BOND_FAIL) >= GEN_7 && gBattleMons[battler].volatiles.destinyBond;
}
// This check has always to be the last in a condtion statement because of the recording of AI data.
@ -10815,7 +10863,7 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, enum Ability abil
u32 nonVolatileStatus = GetMoveNonVolatileStatus(move);
if ((gBattleMons[battlerDef].volatiles.lockOn && gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk)
|| (GetConfig(CONFIG_TOXIC_NEVER_MISS) >= GEN_6 && nonVolatileStatus == MOVE_EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
|| (GetConfig(B_TOXIC_NEVER_MISS) >= GEN_6 && nonVolatileStatus == MOVE_EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
|| gBattleMons[battlerDef].volatiles.glaiveRush)
{
effect = TRUE;
@ -10902,7 +10950,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkA
accStage = gBattleMons[battlerAtk].statStages[STAT_ACC];
evasionStage = gBattleMons[battlerDef].statStages[STAT_EVASION];
if (atkAbility == ABILITY_UNAWARE || atkAbility == ABILITY_KEEN_EYE || atkAbility == ABILITY_MINDS_EYE
|| (GetConfig(CONFIG_ILLUMINATE_EFFECT) >= GEN_9 && atkAbility == ABILITY_ILLUMINATE))
|| (GetConfig(B_ILLUMINATE_EFFECT) >= GEN_9 && atkAbility == ABILITY_ILLUMINATE))
evasionStage = DEFAULT_STAT_STAGE;
if (MoveIgnoresDefenseEvasionStages(move))
evasionStage = DEFAULT_STAT_STAGE;
@ -11078,8 +11126,8 @@ static bool32 IsOpposingSideEmpty(u32 battler)
bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum HoldEffect holdEffect)
{
if ((GetConfig(CONFIG_POWDER_OVERCOAT) >= GEN_6 && ability == ABILITY_OVERCOAT)
|| (GetConfig(CONFIG_POWDER_GRASS) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS))
if ((GetConfig(B_POWDER_OVERCOAT) >= GEN_6 && ability == ABILITY_OVERCOAT)
|| (GetConfig(B_POWDER_GRASS) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS))
|| holdEffect == HOLD_EFFECT_SAFETY_GOGGLES)
return FALSE;
return TRUE;

View File

@ -20,6 +20,7 @@ static u8 BerryTreeGetNumStagesWatered(struct BerryTree *tree);
static u8 GetNumStagesWateredByBerryTreeId(u8 id);
static u8 CalcBerryYieldInternal(u16 max, u16 min, u8 water);
static u8 CalcBerryYield(struct BerryTree *tree);
static u32 GetBerryTreeAge(u8 id, u8 stage);
static u8 GetBerryCountByBerryTreeId(u8 id);
static u16 GetStageDurationByBerryType(u8);
static u8 GetDrainRateByBerryType(u8);
@ -1961,8 +1962,15 @@ void PlantBerryTree(u8 id, u8 berry, u8 stage, bool8 allowGrowth)
tree->stage = stage;
tree->moistureLevel = 100;
if (OW_BERRY_ALWAYS_WATERABLE)
tree->berryYield = GetBerryInfo(berry)->maxYield;
if (stage == BERRY_STAGE_BERRIES)
{
// We simulate a tree having grown without water
u32 berryTreeAge = GetBerryTreeAge(id, stage);
if (GetBerryInfo(berry)->maxYield - berryTreeAge * GetBerryInfo(berry)->maxYield / 5 < GetBerryInfo(berry)->minYield)
tree->berryYield = GetBerryInfo(berry)->minYield;
else
tree->berryYield = GetBerryInfo(berry)->maxYield - berryTreeAge * GetBerryInfo(berry)->maxYield / 5;
}
else if (stage == BERRY_STAGE_BERRIES)
{
tree->berryYield = CalcBerryYield(tree);
tree->minutesUntilNextStage *= ((tree->mulch == ITEM_TO_MULCH(ITEM_STABLE_MULCH)) ? 6 : 4);
@ -2094,6 +2102,17 @@ static u8 CalcBerryYield(struct BerryTree *tree)
return result;
}
static u32 GetBerryTreeAge(u8 id, u8 stage)
{
if (stage == BERRY_STAGE_TRUNK)
stage = 5;
else if (stage == BERRY_STAGE_BUDDING)
stage = 6;
else if (stage > 0)
stage -= 1;
return GetBerryInfo(id)->growthDuration * stage / (OW_BERRY_SIX_STAGES ? 6 : 4);
}
static u8 GetBerryCountByBerryTreeId(u8 id)
{
return gSaveBlock1Ptr->berryTrees[id].berryYield;
@ -2331,7 +2350,6 @@ static const u8 sBerryMutations[][3] = {
{ITEM_TO_BERRY(ITEM_IAPAPA_BERRY), ITEM_TO_BERRY(ITEM_MAGO_BERRY), ITEM_TO_BERRY(ITEM_POMEG_BERRY)},
{ITEM_TO_BERRY(ITEM_CHESTO_BERRY), ITEM_TO_BERRY(ITEM_PERSIM_BERRY), ITEM_TO_BERRY(ITEM_KELPSY_BERRY)},
{ITEM_TO_BERRY(ITEM_ORAN_BERRY), ITEM_TO_BERRY(ITEM_PECHA_BERRY), ITEM_TO_BERRY(ITEM_QUALOT_BERRY)},
{ITEM_TO_BERRY(ITEM_CHESTO_BERRY), ITEM_TO_BERRY(ITEM_PERSIM_BERRY), ITEM_TO_BERRY(ITEM_KELPSY_BERRY)},
{ITEM_TO_BERRY(ITEM_ASPEAR_BERRY), ITEM_TO_BERRY(ITEM_LEPPA_BERRY), ITEM_TO_BERRY(ITEM_HONDEW_BERRY)},
{ITEM_TO_BERRY(ITEM_AGUAV_BERRY), ITEM_TO_BERRY(ITEM_FIGY_BERRY), ITEM_TO_BERRY(ITEM_GREPA_BERRY)},
{ITEM_TO_BERRY(ITEM_LUM_BERRY), ITEM_TO_BERRY(ITEM_SITRUS_BERRY), ITEM_TO_BERRY(ITEM_TAMATO_BERRY)},

View File

@ -9064,8 +9064,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
#endif
.contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED,
.contestCategory = CONTEST_CATEGORY_COOL,
.contestComboStarterId = COMBO_STARTER_CHARGE,
.contestComboMoves = {0},
.contestComboStarterId = 0,
.contestComboMoves = {COMBO_STARTER_CHARGE},
.battleAnimScript = gBattleAnimMove_VoltTackle,
.validApprenticeMove = TRUE,
},
@ -13351,8 +13351,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.category = DAMAGE_CATEGORY_SPECIAL,
.contestEffect = CONTEST_EFFECT_AVOID_STARTLE, //CONTEST_EFFECT_QUICKLY_GROW_BORED
.contestCategory = CONTEST_CATEGORY_COOL,
.contestComboStarterId = COMBO_STARTER_CHARGE,
.contestComboMoves = {0},
.contestComboStarterId = 0,
.contestComboMoves = {COMBO_STARTER_CHARGE},
.battleAnimScript = gBattleAnimMove_VoltSwitch,
},
@ -19483,8 +19483,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
{
.name = COMPOUND_STRING("秘剑千重涛"),
.description = COMPOUND_STRING(
"用贝壳之剑攻击。散落碎片\n"
"会散落在对手脚下成为撒菱。"),
"High critical hit ratio. Sets\n"
"Splinters that hurt the foe."),
.effect = EFFECT_CEASELESS_EDGE,
.power = 65,
.type = TYPE_DARK,

View File

@ -796,13 +796,13 @@ static const struct SpriteFrameImage sPicTable_Steelix[] = {
};
#if P_GENDER_DIFFERENCES
static const struct SpriteFrameImage sPicTable_SteelixF[] = {
overworld_ascending_frames(gObjectEventPic_SteelixF, 4, 4),
overworld_ascending_frames(gObjectEventPic_SteelixF, 8, 8),
};
#endif //P_GENDER_DIFFERENCES
#if OW_BATTLE_ONLY_FORMS
#if P_MEGA_EVOLUTIONS
static const struct SpriteFrameImage sPicTable_SteelixMega[] = {
overworld_ascending_frames(gObjectEventPic_SteelixMega, 4, 4),
overworld_ascending_frames(gObjectEventPic_SteelixMega, 8, 8),
};
#endif // P_MEGA_EVOLUTIONS
#endif // OW_BATTLE_ONLY_FORMS
@ -2994,7 +2994,7 @@ static const struct SpriteFrameImage sPicTable_Latias[] = {
#if OW_BATTLE_ONLY_FORMS
#if P_MEGA_EVOLUTIONS
static const struct SpriteFrameImage sPicTable_LatiasMega[] = {
overworld_ascending_frames(gObjectEventPic_LatiasMega, 4, 4),
overworld_ascending_frames(gObjectEventPic_LatiasMega, 8, 8),
};
#endif // P_MEGA_EVOLUTIONS
#endif // OW_BATTLE_ONLY_FORMS
@ -3007,7 +3007,7 @@ static const struct SpriteFrameImage sPicTable_Latios[] = {
#if OW_BATTLE_ONLY_FORMS
#if P_MEGA_EVOLUTIONS
static const struct SpriteFrameImage sPicTable_LatiosMega[] = {
overworld_ascending_frames(gObjectEventPic_LatiosMega, 4, 4),
overworld_ascending_frames(gObjectEventPic_LatiosMega, 8, 8),
};
#endif // P_MEGA_EVOLUTIONS
#endif // OW_BATTLE_ONLY_FORMS
@ -3020,7 +3020,7 @@ static const struct SpriteFrameImage sPicTable_Kyogre[] = {
#if OW_BATTLE_ONLY_FORMS
#if P_PRIMAL_REVERSIONS
static const struct SpriteFrameImage sPicTable_KyogrePrimal[] = {
overworld_ascending_frames(gObjectEventPic_KyogrePrimal, 4, 4),
overworld_ascending_frames(gObjectEventPic_KyogrePrimal, 8, 8),
};
#endif // P_PRIMAL_REVERSIONS
#endif // OW_BATTLE_ONLY_FORMS
@ -3033,7 +3033,7 @@ static const struct SpriteFrameImage sPicTable_Groudon[] = {
#if OW_BATTLE_ONLY_FORMS
#if P_PRIMAL_REVERSIONS
static const struct SpriteFrameImage sPicTable_GroudonPrimal[] = {
overworld_ascending_frames(gObjectEventPic_GroudonPrimal, 4, 4),
overworld_ascending_frames(gObjectEventPic_GroudonPrimal, 8, 8),
};
#endif // P_PRIMAL_REVERSIONS
#endif // OW_BATTLE_ONLY_FORMS
@ -3046,7 +3046,7 @@ static const struct SpriteFrameImage sPicTable_Rayquaza[] = {
#if OW_BATTLE_ONLY_FORMS
#if P_MEGA_EVOLUTIONS
static const struct SpriteFrameImage sPicTable_RayquazaMega[] = {
overworld_ascending_frames(gObjectEventPic_RayquazaMega, 4, 4),
overworld_ascending_frames(gObjectEventPic_RayquazaMega, 8, 8),
};
#endif // P_MEGA_EVOLUTIONS
#endif // OW_BATTLE_ONLY_FORMS

View File

@ -2255,7 +2255,7 @@ static void DebugAction_Give_PokemonSimple(u8 taskId)
gTasks[taskId].tIsComplex = FALSE;
FreeMonIconPalettes();
LoadMonIconPalette(gTasks[taskId].tInput);
LoadMonIconPalettePersonality(gTasks[taskId].tInput, 0);
gTasks[taskId].tSpriteId = CreateMonIcon(gTasks[taskId].tInput, SpriteCB_MonIcon, DEBUG_NUMBER_ICON_X, DEBUG_NUMBER_ICON_Y, 4, 0);
gSprites[gTasks[taskId].tSpriteId].oam.priority = 0;
}
@ -2289,7 +2289,7 @@ static void DebugAction_Give_PokemonComplex(u8 taskId)
gTasks[taskId].tIsComplex = TRUE;
FreeMonIconPalettes();
LoadMonIconPalette(gTasks[taskId].tInput);
LoadMonIconPalettePersonality(gTasks[taskId].tInput, 0);
gTasks[taskId].tSpriteId = CreateMonIcon(gTasks[taskId].tInput, SpriteCB_MonIcon, DEBUG_NUMBER_ICON_X, DEBUG_NUMBER_ICON_Y, 4, 0);
gSprites[gTasks[taskId].tSpriteId].oam.priority = 0;
gTasks[taskId].tIterator = 0;
@ -2313,7 +2313,7 @@ static void DebugAction_Give_Pokemon_SelectId(u8 taskId)
Debug_Display_SpeciesInfo(gTasks[taskId].tInput, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId);
FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].tSpriteId]);
FreeMonIconPalettes();
LoadMonIconPalette(gTasks[taskId].tInput);
LoadMonIconPalettePersonality(gTasks[taskId].tInput, 0);
gTasks[taskId].tSpriteId = CreateMonIcon(gTasks[taskId].tInput, SpriteCB_MonIcon, DEBUG_NUMBER_ICON_X, DEBUG_NUMBER_ICON_Y, 4, 0);
gSprites[gTasks[taskId].tSpriteId].oam.priority = 0;
}

View File

@ -1971,7 +1971,11 @@ struct Pokemon *GetFirstLiveMon(void)
for (i = 0; i < PARTY_SIZE; i++)
{
struct Pokemon *mon = &gPlayerParty[i];
if ((OW_FOLLOWERS_ALLOWED_SPECIES && GetMonData(mon, MON_DATA_SPECIES_OR_EGG) != VarGet(OW_FOLLOWERS_ALLOWED_SPECIES))
u32 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG);
if (species == SPECIES_NONE)
continue;
if ((OW_FOLLOWERS_ALLOWED_SPECIES && species != VarGet(OW_FOLLOWERS_ALLOWED_SPECIES))
|| (OW_FOLLOWERS_ALLOWED_MET_LVL && GetMonData(mon, MON_DATA_MET_LEVEL) != VarGet(OW_FOLLOWERS_ALLOWED_MET_LVL))
|| (OW_FOLLOWERS_ALLOWED_MET_LOC && GetMonData(mon, MON_DATA_MET_LOCATION) != VarGet(OW_FOLLOWERS_ALLOWED_MET_LOC)))
continue;

View File

@ -277,9 +277,9 @@ static const u8 sRSAvatarGfxIds[GENDER_COUNT] =
[FEMALE] = OBJ_EVENT_GFX_LINK_RS_MAY
};
static const struct __attribute__((packed))
static const struct PACKED
{
u8 graphicsId;
u16 graphicsId;
u8 playerFlag;
} sPlayerAvatarGfxToStateFlag[GENDER_COUNT][5] =
{

View File

@ -3,7 +3,7 @@
#include "malloc.h"
#include "constants/generational_changes.h"
#define UNPACK_CONFIG_GEN_CHANGES2(_name, _field, ...) ._field = B_##_name,
#define UNPACK_CONFIG_GEN_CHANGES2(_name, _field, ...) ._field = _name,
const struct GenChanges sConfigChanges =
{
@ -31,7 +31,7 @@ EWRAM_DATA struct GenChanges *gConfigChangesTestOverride = NULL;
// Gets the value of a volatile status flag for a certain battler
// Primarily used for the debug menu and scripts. Outside of it explicit references are preferred
u32 GetConfig(enum ConfigTag _genConfig)
u32 GetConfigInternal(enum ConfigTag _genConfig)
{
#if TESTING
if (gConfigChangesTestOverride == NULL)

View File

@ -3725,6 +3725,9 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
u8 effectFlags;
s8 evChange;
u16 evCount;
u8 levelBefore;
bool8 didLevelUp = FALSE;
bool8 isLevelUpItem;
// Determine the EV cap to use
u32 maxAllowedEVs = !B_EV_ITEMS_CAP ? MAX_TOTAL_EVS : GetCurrentEVCap();
@ -3746,6 +3749,8 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
// Get item effect
itemEffect = GetItemEffect(item);
isLevelUpItem = (itemEffect[3] & ITEM3_LEVEL_UP) != 0;
levelBefore = GetMonData(mon, MON_DATA_LEVEL, NULL);
// Do item effect
for (i = 0; i < ITEM_EFFECT_ARG_START; i++)
@ -3800,6 +3805,8 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
{
SetMonData(mon, MON_DATA_EXP, &dataUnsigned);
CalculateMonStats(mon);
if (GetMonData(mon, MON_DATA_LEVEL, NULL) > levelBefore)
didLevelUp = TRUE;
retVal = FALSE;
}
}
@ -3918,6 +3925,11 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
{
u32 currentHP = GetMonData(mon, MON_DATA_HP, NULL);
u32 maxHP = GetMonData(mon, MON_DATA_MAX_HP, NULL);
if (isLevelUpItem && !didLevelUp && (effectFlags & (ITEM4_REVIVE >> 2)))
{
itemEffectParam++;
break;
}
// Check use validity.
if ((effectFlags & (ITEM4_REVIVE >> 2) && currentHP != 0)
|| (!(effectFlags & (ITEM4_REVIVE >> 2)) && currentHP == 0))

View File

@ -54,7 +54,7 @@ SINGLE_BATTLE_TEST("Aerilate boosts power of affected moves by 20% (Gen7+) or 30
PARAMETRIZE { move = MOVE_SKILL_SWAP; genConfig = GEN_6; }
GIVEN {
WITH_CONFIG(CONFIG_ATE_MULTIPLIER, genConfig);
WITH_CONFIG(B_ATE_MULTIPLIER, genConfig);
ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL);
ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP);
PLAYER(SPECIES_WOBBUFFET);

View File

@ -47,7 +47,7 @@ SINGLE_BATTLE_TEST("Arena Trap doesn't prevent switch outs via moves that switch
GIVEN {
ASSUME(GetMoveEffect(move) == effect);
ASSUME(GetMoveEffect(MOVE_SOAK) == EFFECT_SOAK);
WITH_CONFIG(CONFIG_TELEPORT_BEHAVIOR, GEN_8);
WITH_CONFIG(B_TELEPORT_BEHAVIOR, GEN_8);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); }
@ -113,7 +113,7 @@ SINGLE_BATTLE_TEST("Arena Trap prevents switch outs from Ghost-type Pokémon (Ge
{
GIVEN {
ASSUME(GetSpeciesType(SPECIES_SHUPPET, 0) == TYPE_GHOST);
WITH_CONFIG(CONFIG_GHOSTS_ESCAPE, GEN_5);
WITH_CONFIG(B_GHOSTS_ESCAPE, GEN_5);
PLAYER(SPECIES_SHUPPET);
OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); }
} WHEN {
@ -129,7 +129,7 @@ SINGLE_BATTLE_TEST("Arena Trap doesn't prevent switch outs from Ghost-type Poké
{
GIVEN {
ASSUME(GetSpeciesType(SPECIES_SHUPPET, 0) == TYPE_GHOST);
WITH_CONFIG(CONFIG_GHOSTS_ESCAPE, GEN_6);
WITH_CONFIG(B_GHOSTS_ESCAPE, GEN_6);
PLAYER(SPECIES_SHUPPET);
OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); }
} WHEN {

View File

@ -17,7 +17,7 @@ SINGLE_BATTLE_TEST("Battle Bond transforms player's Greninja - Singles")
PARAMETRIZE { monsCountPlayer = 2; monsCountOpponent = 2; }
GIVEN {
WITH_CONFIG(CONFIG_BATTLE_BOND, GEN_8);
WITH_CONFIG(B_BATTLE_BOND, GEN_8);
PLAYER(SPECIES_GRENINJA_BATTLE_BOND);
if (monsCountPlayer == 2) {
PLAYER(SPECIES_WOBBUFFET);
@ -65,7 +65,7 @@ SINGLE_BATTLE_TEST("Battle Bond transforms opponent's Greninja - Singles")
PARAMETRIZE { monsCountPlayer = 2; monsCountOpponent = 2; }
GIVEN {
WITH_CONFIG(CONFIG_BATTLE_BOND, GEN_8);
WITH_CONFIG(B_BATTLE_BOND, GEN_8);
OPPONENT(SPECIES_GRENINJA_BATTLE_BOND);
if (monsCountOpponent == 2) {
OPPONENT(SPECIES_WOBBUFFET);
@ -113,7 +113,7 @@ DOUBLE_BATTLE_TEST("Battle Bond transforms player's Greninja when fainting its A
PARAMETRIZE { monsCountPlayer = 3; monsCountOpponent = 3; }
GIVEN {
WITH_CONFIG(CONFIG_BATTLE_BOND, GEN_8);
WITH_CONFIG(B_BATTLE_BOND, GEN_8);
PLAYER(SPECIES_GRENINJA_BATTLE_BOND);
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
if (monsCountPlayer == 3) {
@ -145,7 +145,7 @@ DOUBLE_BATTLE_TEST("Battle Bond transforms player's Greninja when fainting its A
SINGLE_BATTLE_TEST("Battle Bond increases Atk, SpAtk and Speed by 1 stage (Gen9+)")
{
GIVEN {
WITH_CONFIG(CONFIG_BATTLE_BOND, GEN_9);
WITH_CONFIG(B_BATTLE_BOND, GEN_9);
PLAYER(SPECIES_GRENINJA_BATTLE_BOND) { Ability(ABILITY_BATTLE_BOND); }
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
@ -166,7 +166,7 @@ SINGLE_BATTLE_TEST("Battle Bond increases Atk, SpAtk and Speed by 1 stage (Gen9+
SINGLE_BATTLE_TEST("Battle Bond increases a Stat even if only one can be increased (Gen9+)")
{
GIVEN {
WITH_CONFIG(CONFIG_BATTLE_BOND, GEN_9);
WITH_CONFIG(B_BATTLE_BOND, GEN_9);
PLAYER(SPECIES_GRENINJA_BATTLE_BOND) { Ability(ABILITY_BATTLE_BOND); }
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -119,7 +119,7 @@ SINGLE_BATTLE_TEST("Cheek Pouch doesn't activate when using Natural Gift")
}
}
SINGLE_BATTLE_TEST("Cheek Pouch doesn't activate when using Fling")
SINGLE_BATTLE_TEST("Cheek Pouch doesn't activate when user uses Fling")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_FLING) == EFFECT_FLING);

View File

@ -455,3 +455,22 @@ DOUBLE_BATTLE_TEST("Commander prevent Dondozo from switch out by Dragon Tail")
NOT MESSAGE("Wobbuffet was dragged out!");
}
}
DOUBLE_BATTLE_TEST("Commander will not activate if partner Dondozo is about to switch out")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_DONDOZO);
PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
SWITCH(playerLeft, 2);
SWITCH(playerRight, 3);
}
} SCENE {
NOT ABILITY_POPUP(playerRight, ABILITY_COMMANDER);
}
}

View File

@ -140,7 +140,7 @@ SINGLE_BATTLE_TEST("Competitive activates after Sticky Web lowers Speed")
SINGLE_BATTLE_TEST("Competitive doesn't activate after Sticky Web lowers Speed if Court Changed (gen8)")
{
GIVEN {
WITH_CONFIG(CONFIG_DEFIANT_STICKY_WEB, GEN_8);
WITH_CONFIG(B_DEFIANT_STICKY_WEB, GEN_8);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_IGGLYBUFF) { Ability(ABILITY_COMPETITIVE); }
OPPONENT(SPECIES_WOBBUFFET);
@ -167,7 +167,7 @@ SINGLE_BATTLE_TEST("Competitive doesn't activate after Sticky Web lowers Speed i
SINGLE_BATTLE_TEST("Competitive correctly activates after Sticky Web lowers Speed if Court Changed (Gen8)")
{
GIVEN {
WITH_CONFIG(CONFIG_DEFIANT_STICKY_WEB, GEN_8);
WITH_CONFIG(B_DEFIANT_STICKY_WEB, GEN_8);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_IGGLYBUFF) { Ability(ABILITY_COMPETITIVE); }
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -66,34 +66,7 @@ SINGLE_BATTLE_TEST("Corrosion does not effect poison type damaging moves if the
}
}
SINGLE_BATTLE_TEST("Corrosion can poison Poison- and Steel-type targets if it uses Fling while holding a Toxic Orb or a Poison Barb")
{
u16 heldItem;
PARAMETRIZE { heldItem = ITEM_POISON_BARB; }
PARAMETRIZE { heldItem = ITEM_TOXIC_ORB; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_FLING) == EFFECT_FLING);
ASSUME(gItemsInfo[ITEM_POISON_BARB].holdEffect == HOLD_EFFECT_TYPE_POWER);
ASSUME(gItemsInfo[ITEM_POISON_BARB].secondaryId == TYPE_POISON);
ASSUME(gItemsInfo[ITEM_TOXIC_ORB].holdEffect == HOLD_EFFECT_TOXIC_ORB);
PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); Item(heldItem); }
OPPONENT(SPECIES_ODDISH);
} WHEN {
TURN { MOVE(player, MOVE_FLING); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player);
HP_BAR(opponent);
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent);
if (heldItem == ITEM_POISON_BARB)
STATUS_ICON(opponent, poison: TRUE);
else
STATUS_ICON(opponent, badPoison: TRUE);
}
}
SINGLE_BATTLE_TEST("If a Poison- or Steel-type Pokémon with Corrosion holds a Toxic Orb, it will badly poison itself")
SINGLE_BATTLE_TEST("Corrosion badly poisons its Poison/Steel-type user who holds a Toxic Orb")
{
GIVEN {
ASSUME(gItemsInfo[ITEM_TOXIC_ORB].holdEffect == HOLD_EFFECT_TOXIC_ORB);
@ -107,7 +80,7 @@ SINGLE_BATTLE_TEST("If a Poison- or Steel-type Pokémon with Corrosion holds a T
}
}
SINGLE_BATTLE_TEST("If a Poison- or Steel-type Pokémon with Corrosion poisons a target with Synchronize, Synchronize will not poison Poison- or Steel-type Pokémon")
SINGLE_BATTLE_TEST("Corrosion can poison a target with Synchronize and Synchronize will not poison Poison- or Steel-type Pokémon")
{
u16 move;
PARAMETRIZE { move = MOVE_TOXIC; }

View File

@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Cute Charm triggers 1/3 times (Gen3) or 30% (Gen 4+) of the
PARAMETRIZE { config = GEN_4; passes = 3; trials = 10; } // 30%
PASSES_RANDOMLY(passes, trials, RNG_CUTE_CHARM);
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_TRIGGER_CHANCE, config);
WITH_CONFIG(B_ABILITY_TRIGGER_CHANCE, config);
ASSUME(MoveMakesContact(MOVE_SCRATCH));
PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); }
OPPONENT(SPECIES_CLEFAIRY) { Gender(MON_FEMALE); Ability(ABILITY_CUTE_CHARM); }

View File

@ -580,7 +580,7 @@ SINGLE_BATTLE_TEST("Dancer user may hit itself in confusion instead of copying a
PARAMETRIZE { genConfig = GEN_7; pctChance = 33; }
PASSES_RANDOMLY(pctChance, 100, RNG_CONFUSION);
GIVEN {
WITH_CONFIG(CONFIG_CONFUSION_SELF_DMG_CHANCE, genConfig);
WITH_CONFIG(B_CONFUSION_SELF_DMG_CHANCE, genConfig);
ASSUME(IsDanceMove(MOVE_DRAGON_DANCE));
ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE);
PLAYER(SPECIES_WOBBUFFET) { Speed(30); }
@ -747,7 +747,7 @@ SINGLE_BATTLE_TEST("Dancer can still copy status moves if the user is holding an
DOUBLE_BATTLE_TEST("Dancer copies Lunar Dance after the original user faints, but before the replacement is sent out")
{
GIVEN {
WITH_CONFIG(CONFIG_HEALING_WISH_SWITCH, GEN_7);
WITH_CONFIG(B_HEALING_WISH_SWITCH, GEN_7);
ASSUME(GetMoveEffect(MOVE_LUNAR_DANCE) == EFFECT_LUNAR_DANCE);
PLAYER(SPECIES_WOBBUFFET) { Speed(50); }
PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); }

View File

@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Dauntless Shield raises Defense by one stage")
SINGLE_BATTLE_TEST("Dauntless Shield raises Defense by one stage every time it switches in (Gen8)")
{
GIVEN {
WITH_CONFIG(CONFIG_DAUNTLESS_SHIELD, GEN_8);
WITH_CONFIG(B_DAUNTLESS_SHIELD, GEN_8);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ZAMAZENTA) { Ability(ABILITY_DAUNTLESS_SHIELD); }
OPPONENT(SPECIES_WYNAUT);
@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("Dauntless Shield raises Defense by one stage every time it s
SINGLE_BATTLE_TEST("Dauntless Shield raises Defense by one stage only once per battle (Gen 9+)")
{
GIVEN {
WITH_CONFIG(CONFIG_DAUNTLESS_SHIELD, GEN_9);
WITH_CONFIG(B_DAUNTLESS_SHIELD, GEN_9);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ZAMAZENTA) { Ability(ABILITY_DAUNTLESS_SHIELD); }
OPPONENT(SPECIES_WYNAUT);

View File

@ -142,7 +142,7 @@ SINGLE_BATTLE_TEST("Defiant activates after Sticky Web lowers Speed")
SINGLE_BATTLE_TEST("Defiant doesn't activate after Sticky Web lowers Speed if Court Changed (Gen8)")
{
GIVEN {
WITH_CONFIG(CONFIG_DEFIANT_STICKY_WEB, GEN_8);
WITH_CONFIG(B_DEFIANT_STICKY_WEB, GEN_8);
ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN);
ASSUME(GetMoveEffect(MOVE_STICKY_WEB) == EFFECT_STICKY_WEB);
ASSUME(GetMoveEffect(MOVE_COURT_CHANGE) == EFFECT_COURT_CHANGE);
@ -179,7 +179,7 @@ SINGLE_BATTLE_TEST("Defiant doesn't activate after Sticky Web lowers Speed if Co
SINGLE_BATTLE_TEST("Defiant activates after Sticky Web lowers Speed if Court Changed (Gen9)")
{
GIVEN {
WITH_CONFIG(CONFIG_DEFIANT_STICKY_WEB, GEN_9);
WITH_CONFIG(B_DEFIANT_STICKY_WEB, GEN_9);
ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN);
ASSUME(GetMoveEffect(MOVE_STICKY_WEB) == EFFECT_STICKY_WEB);
ASSUME(GetMoveEffect(MOVE_COURT_CHANGE) == EFFECT_COURT_CHANGE);

View File

@ -9,7 +9,7 @@ ASSUMPTIONS
SINGLE_BATTLE_TEST("Disguised Mimikyu doesn't lose 1/8 of its max HP upon changing to its busted form (Gen7)")
{
GIVEN {
WITH_CONFIG(CONFIG_DISGUISE_HP_LOSS, GEN_7);
WITH_CONFIG(B_DISGUISE_HP_LOSS, GEN_7);
PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -29,7 +29,7 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu will lose 1/8 of its max HP upon changing
s16 disguiseDamage;
GIVEN {
WITH_CONFIG(CONFIG_DISGUISE_HP_LOSS, GEN_8);
WITH_CONFIG(B_DISGUISE_HP_LOSS, GEN_8);
PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -26,7 +26,7 @@ SINGLE_BATTLE_TEST("Drizzle summons rain", s16 damage)
SINGLE_BATTLE_TEST("Drizzle sets up rain for 5 turns (Gen6+)")
{
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_6);
PLAYER(SPECIES_POLITOED) { Moves(MOVE_CELEBRATE); Ability(ABILITY_DRIZZLE); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -48,7 +48,7 @@ SINGLE_BATTLE_TEST("Drizzle sets up rain for 5 turns (Gen6+)")
SINGLE_BATTLE_TEST("Drizzle sets up rain for 8 turns with Damp Rock (Gen6+)")
{
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_6);
PLAYER(SPECIES_POLITOED) { Moves(MOVE_CELEBRATE); Ability(ABILITY_DRIZZLE); Item(ITEM_DAMP_ROCK); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -76,7 +76,7 @@ SINGLE_BATTLE_TEST("Drizzle sets up rain for 8 turns with Damp Rock (Gen6+)")
SINGLE_BATTLE_TEST("Drizzle sets up permanent rain (Gen3-5)")
{
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_3);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_3);
PLAYER(SPECIES_POLITOED) { Moves(MOVE_CELEBRATE); Ability(ABILITY_DRIZZLE); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {

View File

@ -4,7 +4,7 @@
SINGLE_BATTLE_TEST("Drought sets up sun for 5 turns (Gen6+)")
{
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_6);
PLAYER(SPECIES_NINETALES) { Moves(MOVE_CELEBRATE); Ability(ABILITY_DROUGHT); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -26,7 +26,7 @@ SINGLE_BATTLE_TEST("Drought sets up sun for 5 turns (Gen6+)")
SINGLE_BATTLE_TEST("Drought sets up sun for 8 turns with Heat Rock (Gen6+)")
{
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_6);
PLAYER(SPECIES_NINETALES) { Moves(MOVE_CELEBRATE); Ability(ABILITY_DROUGHT); Item(ITEM_HEAT_ROCK); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -54,7 +54,7 @@ SINGLE_BATTLE_TEST("Drought sets up sun for 8 turns with Heat Rock (Gen6+)")
SINGLE_BATTLE_TEST("Drought sets up permanent sun (Gen3-5)")
{
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_3);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_3);
PLAYER(SPECIES_NINETALES) { Moves(MOVE_CELEBRATE); Ability(ABILITY_DROUGHT); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {

View File

@ -1,4 +1,49 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Early Bird (Ability) test titles")
SINGLE_BATTLE_TEST("Early Bird wakes up if 1 sleep turn is preset")
{
GIVEN {
PLAYER(SPECIES_DODUO) { Ability(ABILITY_EARLY_BIRD); Status1(STATUS1_SLEEP_TURN(1)); Moves(MOVE_CELEBRATE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_CELEBRATE); }
} SCENE {
MESSAGE("Doduo woke up!");
STATUS_ICON(player, none: TRUE);
MESSAGE("Doduo used Celebrate!");
}
}
SINGLE_BATTLE_TEST("Early Bird turns a 3-turn sleep into one missed turn")
{
GIVEN {
PLAYER(SPECIES_DODUO) { Ability(ABILITY_EARLY_BIRD); Status1(STATUS1_SLEEP_TURN(3)); Moves(MOVE_CELEBRATE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_CELEBRATE); }
TURN { MOVE(player, MOVE_CELEBRATE); }
} SCENE {
MESSAGE("Doduo is fast asleep.");
MESSAGE("Doduo woke up!");
STATUS_ICON(player, none: TRUE);
MESSAGE("Doduo used Celebrate!");
}
}
SINGLE_BATTLE_TEST("Early Bird reduces Rest sleep to one turn")
{
GIVEN {
PLAYER(SPECIES_DODUO) { Ability(ABILITY_EARLY_BIRD); MaxHP(99); HP(66); Moves(MOVE_REST, MOVE_CELEBRATE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_REST); }
TURN { MOVE(player, MOVE_CELEBRATE); }
TURN { MOVE(player, MOVE_CELEBRATE); }
} SCENE {
MESSAGE("Doduo is fast asleep.");
MESSAGE("Doduo woke up!");
STATUS_ICON(player, none: TRUE);
MESSAGE("Doduo used Celebrate!");
}
}

View File

@ -40,7 +40,7 @@ SINGLE_BATTLE_TEST("Effect Spore causes poison 3.3% (Gen3), 10% (Gen4) and 9% (G
PARAMETRIZE { config = GEN_5; passes = 9; trials = 100; } // 9%
PASSES_RANDOMLY(passes, trials, RNG_EFFECT_SPORE);
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_TRIGGER_CHANCE, config);
WITH_CONFIG(B_ABILITY_TRIGGER_CHANCE, config);
ASSUME(MoveMakesContact(MOVE_SCRATCH));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); }
@ -63,7 +63,7 @@ SINGLE_BATTLE_TEST("Effect Spore causes paralysis 3.3% (Gen3) and 10% (Gen4+) of
PARAMETRIZE { config = GEN_5; passes = 1; trials = 10; } // 10%
PASSES_RANDOMLY(passes, trials, RNG_EFFECT_SPORE);
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_TRIGGER_CHANCE, config);
WITH_CONFIG(B_ABILITY_TRIGGER_CHANCE, config);
ASSUME(MoveMakesContact(MOVE_SCRATCH));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); }
@ -86,7 +86,7 @@ SINGLE_BATTLE_TEST("Effect Spore causes sleep 3.3% (Gen3), 10% (Gen4) and 11% (G
PARAMETRIZE { config = GEN_5; passes = 11; trials = 100; } // 11%
PASSES_RANDOMLY(passes, trials, RNG_EFFECT_SPORE);
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_TRIGGER_CHANCE, config);
WITH_CONFIG(B_ABILITY_TRIGGER_CHANCE, config);
ASSUME(MoveMakesContact(MOVE_SCRATCH));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); }
@ -109,7 +109,7 @@ SINGLE_BATTLE_TEST("Effect Spore will check if it can inflict status onto attack
PARAMETRIZE { config = GEN_5; passes = 11; trials = 100; } // 11%
PASSES_RANDOMLY(passes, trials, RNG_EFFECT_SPORE);
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_TRIGGER_CHANCE, config);
WITH_CONFIG(B_ABILITY_TRIGGER_CHANCE, config);
ASSUME(MoveMakesContact(MOVE_SCRATCH));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_BRELOOM) { Status1(STATUS1_BURN); Ability(ABILITY_EFFECT_SPORE); }

View File

@ -209,3 +209,73 @@ WILD_BATTLE_TEST("Emergency Exit activates when taking residual damage and falli
EXPECT_EQ(gBattleOutcome, B_OUTCOME_PLAYER_TELEPORTED);
}
}
SINGLE_BATTLE_TEST("Emergency Exit will trigger due to recoil damage")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_MIND_BLOWN) == EFFECT_MAX_HP_50_RECOIL);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(262); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_MIND_BLOWN); SEND_OUT(opponent, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, opponent);
HP_BAR(player);
HP_BAR(opponent);
ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
}
}
SINGLE_BATTLE_TEST("Emergency Exit will trigger due to confusion damage")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(133); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN {
MOVE(player, MOVE_CONFUSE_RAY);
MOVE(opponent, MOVE_POUND);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, player);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, opponent);
HP_BAR(opponent);
NOT ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
}
}
SINGLE_BATTLE_TEST("Emergency Exit is not triggered by Pain Split")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_PAIN_SPLIT) == EFFECT_PAIN_SPLIT);
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(133); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_PAIN_SPLIT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_PAIN_SPLIT, player);
HP_BAR(opponent);
NOT ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
}
}
SINGLE_BATTLE_TEST("Emergency Exit will trigger due to Jump Kick recoil")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_JUMP_KICK) == EFFECT_RECOIL_IF_MISS);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(262); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_JUMP_KICK, hit: FALSE); SEND_OUT(opponent, 1); }
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_JUMP_KICK, opponent);
HP_BAR(opponent);
ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT);
}
}

View File

@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Flame Body triggers 1/3 times (Gen3) or 30% (Gen 4+) of the
PARAMETRIZE { config = GEN_4; passes = 3; trials = 10; } // 30%
PASSES_RANDOMLY(passes, trials, RNG_FLAME_BODY);
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_TRIGGER_CHANCE, config);
WITH_CONFIG(B_ABILITY_TRIGGER_CHANCE, config);
ASSUME(MoveMakesContact(MOVE_SCRATCH));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_MAGMAR) { Ability(ABILITY_FLAME_BODY); }

View File

@ -1,4 +1,84 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Forewarn (Ability) test titles")
DOUBLE_BATTLE_TEST("Forewarn warns about the highest power move among all opposing battlers")
{
GIVEN {
PLAYER(SPECIES_MUSHARNA) { Ability(ABILITY_FOREWARN); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_ZUBAT) { Moves(MOVE_CRUNCH, MOVE_CELEBRATE); }
OPPONENT(SPECIES_EXCADRILL) { Moves(MOVE_FISSURE, MOVE_CELEBRATE); }
} WHEN {
TURN {}
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_FOREWARN);
MESSAGE("Forewarn alerted Musharna to the opposing Excadrill's Fissure!");
}
}
SINGLE_BATTLE_TEST("Forewarn randomly chooses between same-power moves on one opponent")
{
PASSES_RANDOMLY(1, 3, RNG_FOREWARN);
GIVEN {
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_POUND));
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_SCRATCH));
PLAYER(SPECIES_MUSHARNA) { Ability(ABILITY_FOREWARN); }
OPPONENT(SPECIES_ZUBAT) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_CELEBRATE); }
} WHEN {
TURN {}
} SCENE {
ABILITY_POPUP(player, ABILITY_FOREWARN);
MESSAGE("Forewarn alerted Musharna to the opposing Zubat's Tackle!");
}
}
DOUBLE_BATTLE_TEST("Forewarn randomly chooses between opponents with same-power moves")
{
PASSES_RANDOMLY(1, 4, RNG_FOREWARN);
GIVEN {
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_POUND));
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_SCRATCH));
ASSUME(GetMovePower(MOVE_TACKLE) == GetMovePower(MOVE_QUICK_ATTACK));
PLAYER(SPECIES_MUSHARNA) { Ability(ABILITY_FOREWARN); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_ZUBAT) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_PECK, MOVE_CELEBRATE); }
OPPONENT(SPECIES_EXCADRILL) { Moves(MOVE_SCRATCH, MOVE_QUICK_ATTACK, MOVE_ABSORB, MOVE_CELEBRATE); }
} WHEN {
TURN {}
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_FOREWARN);
MESSAGE("Forewarn alerted Musharna to the opposing Zubat's Tackle!");
}
}
DOUBLE_BATTLE_TEST("Forewarn does not trigger if a mon switches in while the opposing field is empty")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE);
ASSUME(GetMoveEffect(MOVE_HEALING_WISH) == EFFECT_HEALING_WISH);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_MUSHARNA) { Ability(ABILITY_FOREWARN); }
OPPONENT(SPECIES_WYNAUT) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_TREECKO);
OPPONENT(SPECIES_TORCHIC);
} WHEN {
TURN {
MOVE(opponentRight, MOVE_HEALING_WISH);
MOVE(playerLeft, MOVE_U_TURN, target: opponentLeft);
SEND_OUT(playerLeft, 2);
SEND_OUT(opponentLeft, 2);
SEND_OUT(opponentRight, 3);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_HEALING_WISH, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, playerLeft);
HP_BAR(opponentLeft);
NOT ABILITY_POPUP(playerLeft, ABILITY_FOREWARN);
MESSAGE("2 sent out Treecko!");
MESSAGE("2 sent out Torchic!");
NOT ABILITY_POPUP(playerLeft, ABILITY_FOREWARN);
}
}

View File

@ -9,7 +9,7 @@ SINGLE_BATTLE_TEST("Gale Wings only grants priority at full HP (Gen 7+)")
PARAMETRIZE { hp = 100; config = GEN_6; }
PARAMETRIZE { hp = 99; config = GEN_6; }
GIVEN {
WITH_CONFIG(CONFIG_GALE_WINGS, config);
WITH_CONFIG(B_GALE_WINGS, config);
ASSUME(GetMoveType(MOVE_AERIAL_ACE) == TYPE_FLYING);
PLAYER(SPECIES_TALONFLAME) { Ability(ABILITY_GALE_WINGS); HP(hp); MaxHP(100); Speed(1); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }

View File

@ -52,7 +52,7 @@ SINGLE_BATTLE_TEST("Galvanize boosts power of affected moves by 20% (Gen7+) or 3
PARAMETRIZE { ability = ABILITY_GALVANIZE; genConfig = GEN_6; }
GIVEN {
WITH_CONFIG(CONFIG_ATE_MULTIPLIER, genConfig);
WITH_CONFIG(B_ATE_MULTIPLIER, genConfig);
PLAYER(SPECIES_GEODUDE_ALOLA) { Ability(ability); Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Heatproof halves the damage done by burn from 1/8th to 1/16t
PARAMETRIZE { config = GEN_6; burnRate = 16; }
GIVEN {
WITH_CONFIG(CONFIG_BURN_DAMAGE, config);
WITH_CONFIG(B_BURN_DAMAGE, config);
PLAYER (SPECIES_BRONZONG) { Ability(ABILITY_HEATPROOF); Status1(STATUS1_BURN); }
OPPONENT (SPECIES_WOBBUFFET);
}
@ -49,4 +49,3 @@ SINGLE_BATTLE_TEST("Heatproof halves the damage done by burn from 1/8th to 1/16t
HP_BAR(player, damage: maxHP / burnRate);
}
}

View File

@ -117,6 +117,7 @@ SINGLE_BATTLE_TEST("Illusion breaks if user loses Illusion due to Worry Seed")
SINGLE_BATTLE_TEST("Illusion breaks when attacked behind a substitute")
{
GIVEN {
WITH_CONFIG(B_INFILTRATOR_SUBSTITUTE, GEN_6);
PLAYER(SPECIES_DRAGAPULT) { Ability(ABILITY_INFILTRATOR); Speed(1); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
OPPONENT(SPECIES_ZOROARK) { Speed(2); }

View File

@ -1,4 +1,238 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Infiltrator (Ability) test titles")
SINGLE_BATTLE_TEST("Infiltrator bypasses the opponent's Light Screen/Reflect/Aurora Veil", s16 damage)
{
u32 screenMove, attackingMove, ability;
PARAMETRIZE { screenMove = MOVE_LIGHT_SCREEN; attackingMove = MOVE_WATER_GUN; ability = ABILITY_INFILTRATOR; }
PARAMETRIZE { screenMove = MOVE_LIGHT_SCREEN; attackingMove = MOVE_WATER_GUN; ability = ABILITY_CLEAR_BODY; }
PARAMETRIZE { screenMove = MOVE_REFLECT; attackingMove = MOVE_SCRATCH; ability = ABILITY_INFILTRATOR; }
PARAMETRIZE { screenMove = MOVE_REFLECT; attackingMove = MOVE_SCRATCH; ability = ABILITY_CLEAR_BODY; }
PARAMETRIZE { screenMove = MOVE_AURORA_VEIL; attackingMove = MOVE_WATER_GUN; ability = ABILITY_INFILTRATOR; }
PARAMETRIZE { screenMove = MOVE_AURORA_VEIL; attackingMove = MOVE_WATER_GUN; ability = ABILITY_CLEAR_BODY; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_LIGHT_SCREEN) == EFFECT_LIGHT_SCREEN);
ASSUME(GetMoveEffect(MOVE_REFLECT) == EFFECT_REFLECT);
ASSUME(GetMoveEffect(MOVE_AURORA_VEIL) == EFFECT_AURORA_VEIL);
ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL);
ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL);
PLAYER(SPECIES_DRAGAPULT) { Ability(ability); }
OPPONENT(SPECIES_ABOMASNOW) { Ability(ABILITY_SNOW_WARNING); }
} WHEN {
TURN { MOVE(opponent, screenMove); MOVE(player, attackingMove); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, screenMove, opponent);
ANIMATION(ANIM_TYPE_MOVE, attackingMove, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, UQ_4_12(0.5), results[1].damage);
EXPECT_MUL_EQ(results[2].damage, UQ_4_12(0.5), results[3].damage);
EXPECT_MUL_EQ(results[4].damage, UQ_4_12(0.5), results[5].damage);
}
}
DOUBLE_BATTLE_TEST("Infiltrator doesn't bypass an ally's Light Screen/Reflect/Aurora Veil", s16 damage)
{
u32 screenMove, attackingMove, ability;
PARAMETRIZE { screenMove = MOVE_LIGHT_SCREEN; attackingMove = MOVE_WATER_GUN; ability = ABILITY_INFILTRATOR; }
PARAMETRIZE { screenMove = MOVE_LIGHT_SCREEN; attackingMove = MOVE_WATER_GUN; ability = ABILITY_CLEAR_BODY; }
PARAMETRIZE { screenMove = MOVE_REFLECT; attackingMove = MOVE_SCRATCH; ability = ABILITY_INFILTRATOR; }
PARAMETRIZE { screenMove = MOVE_REFLECT; attackingMove = MOVE_SCRATCH; ability = ABILITY_CLEAR_BODY; }
PARAMETRIZE { screenMove = MOVE_AURORA_VEIL; attackingMove = MOVE_WATER_GUN; ability = ABILITY_INFILTRATOR; }
PARAMETRIZE { screenMove = MOVE_AURORA_VEIL; attackingMove = MOVE_WATER_GUN; ability = ABILITY_CLEAR_BODY; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_LIGHT_SCREEN) == EFFECT_LIGHT_SCREEN);
ASSUME(GetMoveEffect(MOVE_REFLECT) == EFFECT_REFLECT);
ASSUME(GetMoveEffect(MOVE_AURORA_VEIL) == EFFECT_AURORA_VEIL);
ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL);
ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL);
PLAYER(SPECIES_DRAGAPULT) { Ability(ability); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ABOMASNOW) { Ability(ABILITY_SNOW_WARNING); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(playerRight, screenMove); MOVE(playerLeft, attackingMove, target: playerRight); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, screenMove, playerRight);
ANIMATION(ANIM_TYPE_MOVE, attackingMove, playerLeft);
HP_BAR(playerRight, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_EQ(results[0].damage, results[1].damage);
EXPECT_EQ(results[2].damage, results[3].damage);
EXPECT_EQ(results[4].damage, results[5].damage);
}
}
SINGLE_BATTLE_TEST("Infiltrator bypasses the opponent's Mist")
{
u32 ability;
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_MIST) == EFFECT_MIST);
ASSUME(GetMoveEffect(MOVE_SCREECH) == EFFECT_DEFENSE_DOWN_2);
PLAYER(SPECIES_DRAGAPULT) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_MIST); MOVE(player, MOVE_SCREECH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIST, opponent);
if (ability == ABILITY_INFILTRATOR)
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCREECH, player);
else
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SCREECH, player);
}
}
DOUBLE_BATTLE_TEST("Infiltrator doesn't bypass an ally's Mist")
{
u32 ability;
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_MIST) == EFFECT_MIST);
ASSUME(GetMoveEffect(MOVE_SCREECH) == EFFECT_DEFENSE_DOWN_2);
PLAYER(SPECIES_DRAGAPULT) { Ability(ability); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(playerRight, MOVE_MIST); MOVE(playerLeft, MOVE_SCREECH, target: playerRight); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIST, playerRight);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SCREECH, playerLeft);
}
}
SINGLE_BATTLE_TEST("Infiltrator bypasses the opponent's Safeguard")
{
u32 ability;
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_SAFEGUARD) == EFFECT_SAFEGUARD);
ASSUME(GetMoveEffect(MOVE_THUNDER_WAVE) == EFFECT_NON_VOLATILE_STATUS);
PLAYER(SPECIES_DRAGAPULT) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SAFEGUARD); MOVE(player, MOVE_THUNDER_WAVE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SAFEGUARD, opponent);
if (ability == ABILITY_INFILTRATOR)
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_WAVE, player);
else
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_WAVE, player);
}
}
DOUBLE_BATTLE_TEST("Infiltrator doesn't bypass an ally's Safeguard")
{
u32 ability;
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_SAFEGUARD) == EFFECT_SAFEGUARD);
ASSUME(GetMoveEffect(MOVE_THUNDER_WAVE) == EFFECT_NON_VOLATILE_STATUS);
PLAYER(SPECIES_DRAGAPULT) { Ability(ability); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(playerRight, MOVE_SAFEGUARD); MOVE(playerLeft, MOVE_THUNDER_WAVE, target: playerRight); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SAFEGUARD, playerRight);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_WAVE, playerLeft);
}
}
SINGLE_BATTLE_TEST("Infiltrator bypasses the opponent's Substitute (Gen 6+)")
{
u32 ability, config;
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; config = GEN_5; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; config = GEN_5; }
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; config = GEN_6; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; config = GEN_6; }
GIVEN {
WITH_CONFIG(B_INFILTRATOR_SUBSTITUTE, config);
ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE);
ASSUME(!MoveIgnoresSubstitute(MOVE_SCRATCH));
PLAYER(SPECIES_DRAGAPULT) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_SCRATCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
if (ability == ABILITY_INFILTRATOR && config >= GEN_6) {
NOT SUB_HIT(opponent);
} else {
SUB_HIT(opponent);
}
}
}
DOUBLE_BATTLE_TEST("Infiltrator bypasses an ally's Substitute (Gen 6+)")
{
u32 ability, config;
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; config = GEN_5; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; config = GEN_5; }
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; config = GEN_6; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; config = GEN_6; }
GIVEN {
WITH_CONFIG(B_INFILTRATOR_SUBSTITUTE, config);
ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE);
ASSUME(!MoveIgnoresSubstitute(MOVE_SCRATCH));
PLAYER(SPECIES_DRAGAPULT) { Ability(ability); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(playerRight, MOVE_SUBSTITUTE); MOVE(playerLeft, MOVE_SCRATCH, target: playerRight); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, playerRight);
if (ability == ABILITY_INFILTRATOR && config == GEN_6) {
NOT SUB_HIT(playerRight);
} else {
SUB_HIT(playerRight);
}
}
}
SINGLE_BATTLE_TEST("Infiltrator doesn't ignore a battler's Substitute when using Transform or Sky Drop")
{
u32 ability, move;
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; move = MOVE_TRANSFORM; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; move = MOVE_TRANSFORM; }
PARAMETRIZE { ability = ABILITY_CLEAR_BODY; move = MOVE_SKY_DROP; }
PARAMETRIZE { ability = ABILITY_INFILTRATOR; move = MOVE_SKY_DROP; }
GIVEN {
WITH_CONFIG(B_INFILTRATOR_SUBSTITUTE, GEN_6);
ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE);
ASSUME(GetMoveEffect(MOVE_TRANSFORM) == EFFECT_TRANSFORM);
ASSUME(GetMoveEffect(MOVE_SKY_DROP) == EFFECT_SKY_DROP);
PLAYER(SPECIES_DRAGAPULT) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
NOT ANIMATION(ANIM_TYPE_MOVE, move, player);
}
}

View File

@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Inner Focus doesn't prevent intimidate (Gen3-7)")
s16 turnTwoHit;
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_7);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_7);
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); }
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_ZUBAT) { Ability(ABILITY_INNER_FOCUS); }
@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Inner Focus prevents intimidate (Gen8+)")
s16 turnTwoHit;
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_8);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_8);
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); }
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_ZUBAT) { Ability(ABILITY_INNER_FOCUS); }

View File

@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Intrepid Sword raises Attack by one stage")
SINGLE_BATTLE_TEST("Intrepid Sword raises Attack by one stage every time it switches in (Gen8)")
{
GIVEN {
WITH_CONFIG(CONFIG_INTREPID_SWORD, GEN_8);
WITH_CONFIG(B_INTREPID_SWORD, GEN_8);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
OPPONENT(SPECIES_WYNAUT);
@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("Intrepid Sword raises Attack by one stage every time it swit
SINGLE_BATTLE_TEST("Intrepid Sword raises Attack by one stage only once per battle (Gen9+)")
{
GIVEN {
WITH_CONFIG(CONFIG_INTREPID_SWORD, GEN_9);
WITH_CONFIG(B_INTREPID_SWORD, GEN_9);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); }
OPPONENT(SPECIES_WYNAUT);

View File

@ -18,7 +18,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye prevent accuracy stag
PASSES_RANDOMLY(100, 100, RNG_ACCURACY);
GIVEN {
WITH_CONFIG(CONFIG_ILLUMINATE_EFFECT, GEN_9);
WITH_CONFIG(B_ILLUMINATE_EFFECT, GEN_9);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
} WHEN {
@ -47,7 +47,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye ignore target's evasi
PASSES_RANDOMLY(100, 100, RNG_ACCURACY);
GIVEN {
WITH_CONFIG(CONFIG_ILLUMINATE_EFFECT, GEN_9);
WITH_CONFIG(B_ILLUMINATE_EFFECT, GEN_9);
ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
@ -81,7 +81,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye are ignored by Mold B
PASSES_RANDOMLY(GetMoveAccuracy(MOVE_SCRATCH) * 3 / 4, 100, RNG_ACCURACY);
GIVEN {
WITH_CONFIG(CONFIG_ILLUMINATE_EFFECT, GEN_9);
WITH_CONFIG(B_ILLUMINATE_EFFECT, GEN_9);
PLAYER(speciesPlayer) { Ability(abilityPlayer); }
OPPONENT(speciesOpponent) { Ability(abilityOpponent); }
} WHEN {
@ -104,7 +104,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye don't prevent Topsy-T
PARAMETRIZE { species = SPECIES_URSALUNA_BLOODMOON; ability = ABILITY_MINDS_EYE; }
GIVEN {
WITH_CONFIG(CONFIG_ILLUMINATE_EFFECT, GEN_9);
WITH_CONFIG(B_ILLUMINATE_EFFECT, GEN_9);
ASSUME(GetMoveEffect(MOVE_HONE_CLAWS) == EFFECT_ATTACK_ACCURACY_UP);
ASSUME(GetMoveEffect(MOVE_TOPSY_TURVY) == EFFECT_TOPSY_TURVY);
PLAYER(SPECIES_WOBBUFFET);
@ -144,7 +144,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye don't prevent receivi
PARAMETRIZE { species = SPECIES_URSALUNA_BLOODMOON; ability = ABILITY_MINDS_EYE; }
GIVEN {
WITH_CONFIG(CONFIG_ILLUMINATE_EFFECT, GEN_9);
WITH_CONFIG(B_ILLUMINATE_EFFECT, GEN_9);
ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@ -177,7 +177,7 @@ SINGLE_BATTLE_TEST("Keen Eye & Gen9+ Illuminate don't prevent Spectral Thief fro
PARAMETRIZE { species = SPECIES_STARYU; ability = ABILITY_ILLUMINATE; }
GIVEN {
WITH_CONFIG(CONFIG_ILLUMINATE_EFFECT, GEN_9);
WITH_CONFIG(B_ILLUMINATE_EFFECT, GEN_9);
ASSUME(GetMoveEffect(MOVE_HONE_CLAWS) == EFFECT_ATTACK_ACCURACY_UP);
ASSUME(GetMoveEffect(MOVE_SPECTRAL_THIEF) == EFFECT_SPECTRAL_THIEF);
PLAYER(SPECIES_WOBBUFFET);

View File

@ -121,7 +121,7 @@ SINGLE_BATTLE_TEST("Leaf Guard prevents Rest during sun (Gen 5+)")
PARAMETRIZE { gen = GEN_4; }
PARAMETRIZE { gen = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_LEAF_GUARD_PREVENTS_REST, gen);
WITH_CONFIG(B_LEAF_GUARD_PREVENTS_REST, gen);
ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST);
PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); HP(100); MaxHP(200); }
OPPONENT(SPECIES_WOBBUFFET);
@ -151,7 +151,7 @@ SINGLE_BATTLE_TEST("Leaf Guard doesn't prevent Rest if Cloud Nine/Air Lock is on
PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; }
PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; }
GIVEN {
WITH_CONFIG(CONFIG_LEAF_GUARD_PREVENTS_REST, GEN_5);
WITH_CONFIG(B_LEAF_GUARD_PREVENTS_REST, GEN_5);
ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST);
PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); HP(100); MaxHP(200); }
OPPONENT(species) { Ability(ability); }

View File

@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Lightning Rod absorbs Electric-type moves and increases the
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
WITH_CONFIG(B_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); }
@ -47,7 +47,7 @@ DOUBLE_BATTLE_TEST("Lightning Rod forces single-target Electric-type moves to ta
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
WITH_CONFIG(B_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
@ -115,7 +115,7 @@ DOUBLE_BATTLE_TEST("Lightning Rod redirects an ally's attack")
DOUBLE_BATTLE_TEST("Lightning Rod absorbs moves that targets all battlers but does not redirect (Gen6+)")
{
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
WITH_CONFIG(B_REDIRECT_ABILITY_IMMUNITY, GEN_5);
ASSUME(GetMoveType(MOVE_DISCHARGE) == TYPE_ELECTRIC);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);

View File

@ -142,7 +142,7 @@ SINGLE_BATTLE_TEST("Liquid Ooze causes Dream Eater users to lose HP instead of h
{
s16 damage;
GIVEN {
WITH_CONFIG(CONFIG_DREAM_EATER_LIQUID_OOZE, GEN_5);
WITH_CONFIG(B_DREAM_EATER_LIQUID_OOZE, GEN_5);
ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_NON_VOLATILE_STATUS);
ASSUME(GetMoveNonVolatileStatus(MOVE_SPORE) == MOVE_EFFECT_SLEEP);
ASSUME(GetMoveEffect(MOVE_DREAM_EATER) == EFFECT_DREAM_EATER);
@ -167,7 +167,7 @@ SINGLE_BATTLE_TEST("Liquid Ooze does not cause Dream Eater users to lose HP inst
{
s16 damage;
GIVEN {
WITH_CONFIG(CONFIG_DREAM_EATER_LIQUID_OOZE, GEN_3);
WITH_CONFIG(B_DREAM_EATER_LIQUID_OOZE, GEN_3);
ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_NON_VOLATILE_STATUS);
ASSUME(GetMoveNonVolatileStatus(MOVE_SPORE) == MOVE_EFFECT_SLEEP);
ASSUME(GetMoveEffect(MOVE_DREAM_EATER) == EFFECT_DREAM_EATER);

View File

@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("Magic Bounce bounces back powder moves")
SINGLE_BATTLE_TEST("Magic Bounce cannot bounce back powder moves against Grass Types")
{
GIVEN {
WITH_CONFIG(CONFIG_POWDER_GRASS, GEN_6);
WITH_CONFIG(B_POWDER_GRASS, GEN_6);
ASSUME(IsPowderMove(MOVE_STUN_SPORE));
ASSUME(GetSpeciesType(SPECIES_ODDISH, 0) == TYPE_GRASS);
PLAYER(SPECIES_ODDISH);

View File

@ -11,7 +11,7 @@ SINGLE_BATTLE_TEST("Moody randomly raises the user's Attack, Defense, Sp. Atk, S
// HP is not included
PASSES_RANDOMLY(1, statsNum - 1, RNG_MOODY_INCREASE);
GIVEN {
WITH_CONFIG(CONFIG_MOODY_ACC_EVASION, config);
WITH_CONFIG(B_MOODY_ACC_EVASION, config);
PLAYER(SPECIES_OCTILLERY) { Ability(ABILITY_MOODY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -36,7 +36,7 @@ SINGLE_BATTLE_TEST("Moody randomly lowers the user's Attack, Defense, Sp. Atk, S
// One stat becomes unavailable due to it already increasing
PASSES_RANDOMLY(1, statsNum - 2, RNG_MOODY_DECREASE);
GIVEN {
WITH_CONFIG(CONFIG_MOODY_ACC_EVASION, config);
WITH_CONFIG(B_MOODY_ACC_EVASION, config);
PLAYER(SPECIES_OCTILLERY) { Ability(ABILITY_MOODY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -60,7 +60,7 @@ SINGLE_BATTLE_TEST("Moody randomly raises the holder's Attack, Defense, Sp. Atk,
PASSES_RANDOMLY(statsNum - 1, statsNum - 1, RNG_MOODY_DECREASE);
GIVEN {
WITH_CONFIG(CONFIG_MOODY_ACC_EVASION, config);
WITH_CONFIG(B_MOODY_ACC_EVASION, config);
PLAYER(SPECIES_OCTILLERY) { Ability(ABILITY_MOODY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -87,7 +87,7 @@ SINGLE_BATTLE_TEST("Normalize doesn't boost power of unaffected moves by 20% (<
PARAMETRIZE { ability = ABILITY_NORMALIZE; }
GIVEN {
WITH_CONFIG(CONFIG_ATE_MULTIPLIER, GEN_6);
WITH_CONFIG(B_ATE_MULTIPLIER, GEN_6);
PLAYER(SPECIES_DELCATTY) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -106,7 +106,7 @@ SINGLE_BATTLE_TEST("Normalize boosts power of unaffected moves by 20% (Gen7+)",
PARAMETRIZE { ability = ABILITY_NORMALIZE; }
GIVEN {
WITH_CONFIG(CONFIG_ATE_MULTIPLIER, GEN_7);
WITH_CONFIG(B_ATE_MULTIPLIER, GEN_7);
PLAYER(SPECIES_DELCATTY) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -125,7 +125,7 @@ SINGLE_BATTLE_TEST("Normalize doesn't boost power of affected moves by 20% (< Ge
PARAMETRIZE { ability = ABILITY_NORMALIZE; }
GIVEN {
WITH_CONFIG(CONFIG_ATE_MULTIPLIER, GEN_6);
WITH_CONFIG(B_ATE_MULTIPLIER, GEN_6);
PLAYER(SPECIES_SKITTY) { Ability(ability); Moves(MOVE_WATER_GUN); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -144,7 +144,7 @@ SINGLE_BATTLE_TEST("Normalize boosts power of affected moves by 20% (Gen7+)", s1
PARAMETRIZE { ability = ABILITY_NORMALIZE; }
GIVEN {
WITH_CONFIG(CONFIG_ATE_MULTIPLIER, GEN_7);
WITH_CONFIG(B_ATE_MULTIPLIER, GEN_7);
PLAYER(SPECIES_SKITTY) { Ability(ability); Moves(MOVE_WATER_GUN); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Oblivious prevents Taunt (Gen6+)")
PARAMETRIZE { gen = GEN_5; }
PARAMETRIZE { gen = GEN_6; }
GIVEN {
WITH_CONFIG(CONFIG_OBLIVIOUS_TAUNT, gen);
WITH_CONFIG(B_OBLIVIOUS_TAUNT, gen);
ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT);
PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OBLIVIOUS); }
OPPONENT(SPECIES_WOBBUFFET);
@ -66,7 +66,7 @@ SINGLE_BATTLE_TEST("Oblivious prevents Taunt (Gen6+)")
SINGLE_BATTLE_TEST("Oblivious doesn't prevent Intimidate (Gen3-7)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_7);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_7);
PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OBLIVIOUS); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
@ -86,7 +86,7 @@ SINGLE_BATTLE_TEST("Oblivious doesn't prevent Intimidate (Gen3-7)")
SINGLE_BATTLE_TEST("Oblivious prevents Intimidate (Gen8+)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_8);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_8);
PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OBLIVIOUS); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }

View File

@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Overcoat blocks powder and spore moves (Gen6+)")
PARAMETRIZE { gen = GEN_5; }
PARAMETRIZE { gen = GEN_6; }
GIVEN {
WITH_CONFIG(CONFIG_POWDER_OVERCOAT, gen);
WITH_CONFIG(B_POWDER_OVERCOAT, gen);
ASSUME(IsPowderMove(MOVE_STUN_SPORE));
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_PINECO) { Ability(ABILITY_OVERCOAT); }
@ -77,7 +77,7 @@ SINGLE_BATTLE_TEST("Overcoat blocks Effect Spore's effect (Gen6+)")
PARAMETRIZE { config = GEN_5; }
PARAMETRIZE { config = GEN_6; }
GIVEN {
WITH_CONFIG(CONFIG_POWDER_OVERCOAT, config);
WITH_CONFIG(B_POWDER_OVERCOAT, config);
PLAYER(SPECIES_PINECO) { Ability(ABILITY_OVERCOAT); }
OPPONENT(SPECIES_SHROOMISH) { Ability(ABILITY_EFFECT_SPORE); }
} WHEN {

View File

@ -4,7 +4,7 @@
SINGLE_BATTLE_TEST("Own Tempo doesn't prevent Intimidate (Gen3-7)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_7);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_7);
ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE);
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); }
@ -22,7 +22,7 @@ SINGLE_BATTLE_TEST("Own Tempo doesn't prevent Intimidate (Gen3-7)")
SINGLE_BATTLE_TEST("Own Tempo prevents Intimidate but no other stat down changes (Gen8+)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_8);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_8);
ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE);
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); }

View File

@ -111,7 +111,7 @@ SINGLE_BATTLE_TEST("Parental Bond-converted moves only hit once on Lightning Rod
PARAMETRIZE { move = MOVE_THUNDERBOLT; ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; type = TYPE_ELECTRIC; }
PARAMETRIZE { move = MOVE_SURF; ability = ABILITY_STORM_DRAIN; species = SPECIES_LILEEP; type = TYPE_WATER; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, GEN_5);
WITH_CONFIG(B_REDIRECT_ABILITY_IMMUNITY, GEN_5);
ASSUME(GetMoveStrikeCount(move) < 2);
ASSUME(GetMoveType(move) == type);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }
@ -142,7 +142,7 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
WITH_CONFIG(CONFIG_MULTI_HIT_CHANCE, genConfig);
WITH_CONFIG(B_MULTI_HIT_CHANCE, genConfig);
ASSUME(GetMoveCategory(MOVE_COMET_PUNCH) != DAMAGE_CATEGORY_STATUS);
ASSUME(GetMoveEffect(MOVE_COMET_PUNCH) == EFFECT_MULTI_HIT);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }
@ -171,7 +171,7 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
WITH_CONFIG(CONFIG_MULTI_HIT_CHANCE, genConfig);
WITH_CONFIG(B_MULTI_HIT_CHANCE, genConfig);
ASSUME(GetMoveCategory(MOVE_COMET_PUNCH) != DAMAGE_CATEGORY_STATUS);
ASSUME(GetMoveEffect(MOVE_COMET_PUNCH) == EFFECT_MULTI_HIT);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }
@ -201,7 +201,7 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
WITH_CONFIG(CONFIG_MULTI_HIT_CHANCE, genConfig);
WITH_CONFIG(B_MULTI_HIT_CHANCE, genConfig);
ASSUME(GetMoveCategory(MOVE_COMET_PUNCH) != DAMAGE_CATEGORY_STATUS);
ASSUME(GetMoveEffect(MOVE_COMET_PUNCH) == EFFECT_MULTI_HIT);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }
@ -232,7 +232,7 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
WITH_CONFIG(CONFIG_MULTI_HIT_CHANCE, genConfig);
WITH_CONFIG(B_MULTI_HIT_CHANCE, genConfig);
ASSUME(GetMoveCategory(MOVE_COMET_PUNCH) != DAMAGE_CATEGORY_STATUS);
ASSUME(GetMoveEffect(MOVE_COMET_PUNCH) == EFFECT_MULTI_HIT);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }

View File

@ -1,4 +1,312 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("TODO: Write Pickpocket (Ability) test titles")
ASSUMPTIONS
{
ASSUME(MoveMakesContact(MOVE_BREAKING_SWIPE));
ASSUME(MoveMakesContact(MOVE_SCRATCH));
}
DOUBLE_BATTLE_TEST("Pickpocket checks contact/effect per target for spread moves")
{
GIVEN {
ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY);
ASSUME(GetMoveType(MOVE_BREAKING_SWIPE) == TYPE_DRAGON);
ASSUME(GetMoveTarget(MOVE_BREAKING_SWIPE) == MOVE_TARGET_BOTH);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
OPPONENT(SPECIES_CLEFAIRY);
} WHEN {
TURN { MOVE(playerLeft, MOVE_BREAKING_SWIPE); }
} SCENE {
ABILITY_POPUP(opponentLeft, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
} THEN {
EXPECT(opponentLeft->item == ITEM_MAGOST_BERRY);
EXPECT(playerLeft->item == ITEM_NONE);
}
}
DOUBLE_BATTLE_TEST("Pickpocket activates for the fastest itemless target when both are hit by a contact spread move")
{
GIVEN {
ASSUME(GetMoveTarget(MOVE_BREAKING_SWIPE) == MOVE_TARGET_BOTH);
PLAYER(SPECIES_WOBBUFFET) { Speed(20); Item(ITEM_MAGOST_BERRY); }
PLAYER(SPECIES_WYNAUT) { Speed(10); }
OPPONENT(SPECIES_SNEASEL) { Speed(40); Ability(ABILITY_PICKPOCKET); }
OPPONENT(SPECIES_SNEASEL) { Speed(30); Ability(ABILITY_PICKPOCKET); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_BREAKING_SWIPE); }
} SCENE {
ABILITY_POPUP(opponentLeft, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
} THEN {
EXPECT(opponentLeft->item == ITEM_MAGOST_BERRY);
EXPECT(opponentRight->item == ITEM_NONE);
EXPECT(playerLeft->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket steals the attacker's item unless it already has one")
{
bool32 targetHasItem;
PARAMETRIZE { targetHasItem = FALSE; }
PARAMETRIZE { targetHasItem = TRUE; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(targetHasItem ? ITEM_EVIOLITE : ITEM_NONE); }
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
if (targetHasItem) {
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
}
} else {
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
}
} THEN {
if (targetHasItem) {
EXPECT(opponent->item == ITEM_EVIOLITE);
EXPECT(player->item == ITEM_MAGOST_BERRY);
} else {
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
EXPECT(player->item == ITEM_NONE);
}
}
}
SINGLE_BATTLE_TEST("Pickpocket does not activate if the user faints")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); HP(1); }
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
}
MESSAGE("The opposing Sneasel fainted!");
} THEN {
EXPECT(opponent->item == ITEM_NONE);
EXPECT(player->item == ITEM_MAGOST_BERRY);
}
}
SINGLE_BATTLE_TEST("Pickpocket cannot steal from Sticky Hold")
{
GIVEN {
PLAYER(SPECIES_GRIMER) { Ability(ABILITY_STICKY_HOLD); Item(ITEM_MAGOST_BERRY); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
ABILITY_POPUP(player, ABILITY_STICKY_HOLD);
MESSAGE("Grimer's item cannot be removed!");
} THEN {
EXPECT(opponent->item == ITEM_NONE);
EXPECT(player->item == ITEM_MAGOST_BERRY);
}
}
SINGLE_BATTLE_TEST("Pickpocket cannot steal restricted held items")
{
GIVEN {
ASSUME(gItemsInfo[ITEM_NORMALIUM_Z].holdEffect == HOLD_EFFECT_Z_CRYSTAL);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
}
} THEN {
EXPECT(opponent->item == ITEM_NONE);
EXPECT(player->item == ITEM_NORMALIUM_Z);
}
}
SINGLE_BATTLE_TEST("Pickpocket activates after the final hit of a multi-strike move")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_FURY_SWIPES) == EFFECT_MULTI_HIT);
ASSUME(MoveMakesContact(MOVE_FURY_SWIPES));
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
} WHEN {
TURN { MOVE(player, MOVE_FURY_SWIPES, WITH_RNG(RNG_HITS, 3)); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, player);
MESSAGE("The Pokémon was hit 3 time(s)!");
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
} THEN {
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
EXPECT(player->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket activates after Magician steals an item")
{
GIVEN {
PLAYER(SPECIES_DELPHOX) { Ability(ABILITY_MAGICIAN); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_MAGOST_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
ABILITY_POPUP(player, ABILITY_MAGICIAN);
MESSAGE("Delphox stole the opposing Sneasel's Magost Berry!");
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Delphox's Magost Berry!");
} THEN {
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
EXPECT(player->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket activates after Sticky Barb transfers")
{
GIVEN {
ASSUME(gItemsInfo[ITEM_STICKY_BARB].holdEffect == HOLD_EFFECT_STICKY_BARB);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_STICKY_BARB); }
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
MESSAGE("The Sticky Barb attached itself to Wobbuffet!");
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Sticky Barb!");
} THEN {
EXPECT(opponent->item == ITEM_STICKY_BARB);
EXPECT(player->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket activates after Thief or Covet steals an item")
{
u16 move;
PARAMETRIZE { move = MOVE_THIEF; }
PARAMETRIZE { move = MOVE_COVET; }
GIVEN {
ASSUME(GetMoveEffect(move) == EFFECT_STEAL_ITEM);
ASSUME(MoveMakesContact(move));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_MAGOST_BERRY); }
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
MESSAGE("Wobbuffet stole the opposing Sneasel's Magost Berry!");
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
} THEN {
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
EXPECT(player->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket activates after Focus Sash is consumed")
{
GIVEN {
ASSUME(MoveMakesContact(MOVE_SEISMIC_TOSS));
ASSUME(gItemsInfo[ITEM_FOCUS_SASH].holdEffect == HOLD_EFFECT_FOCUS_SASH);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); Level(100); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_FOCUS_SASH); MaxHP(6); HP(6); }
} WHEN {
TURN { MOVE(player, MOVE_SEISMIC_TOSS); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEISMIC_TOSS, player);
MESSAGE("The opposing Sneasel hung on using its Focus Sash!");
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
} THEN {
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
EXPECT(player->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket activates after Knock Off, Bug Bite, or Pluck")
{
u16 move;
PARAMETRIZE { move = MOVE_KNOCK_OFF; }
PARAMETRIZE { move = MOVE_BUG_BITE; }
PARAMETRIZE { move = MOVE_PLUCK; }
GIVEN {
ASSUME(MoveMakesContact(move));
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_ORAN_BERRY); }
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
} THEN {
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
EXPECT(player->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket steals Life Orb after it activates")
{
GIVEN {
ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
MESSAGE("Wobbuffet was hurt by the Life Orb!");
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Life Orb!");
} THEN {
EXPECT(opponent->item == ITEM_LIFE_ORB);
EXPECT(player->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket steals Shell Bell after it heals the user")
{
GIVEN {
ASSUME(gItemsInfo[ITEM_SHELL_BELL].holdEffect == HOLD_EFFECT_SHELL_BELL);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SHELL_BELL); MaxHP(100); HP(66); }
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
HP_BAR(opponent);
HP_BAR(player);
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's Shell Bell!");
} THEN {
EXPECT(opponent->item == ITEM_SHELL_BELL);
EXPECT(player->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket does not prevent King's Rock or Razor Fang flinches")
{
GIVEN {
ASSUME(gItemsInfo[ITEM_KINGS_ROCK].holdEffect == HOLD_EFFECT_FLINCH);
PLAYER(SPECIES_WOBBUFFET) { Speed(20); Item(ITEM_KINGS_ROCK); }
OPPONENT(SPECIES_SNEASEL) { Speed(10); Ability(ABILITY_PICKPOCKET); }
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH, WITH_RNG(RNG_HOLD_EFFECT_FLINCH, 1)); MOVE(opponent, MOVE_SCRATCH); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
MESSAGE("The opposing Sneasel stole Wobbuffet's King's Rock!");
MESSAGE("The opposing Sneasel flinched and couldn't move!");
} THEN {
EXPECT(opponent->item == ITEM_KINGS_ROCK);
EXPECT(player->item == ITEM_NONE);
}
}

View File

@ -26,7 +26,7 @@ SINGLE_BATTLE_TEST("Pickup grants an item used by another Pokémon")
WILD_BATTLE_TEST("Pickup grants an item used by itself in wild battles (Gen9+)")
{
GIVEN {
WITH_CONFIG(CONFIG_PICKUP_WILD, GEN_9);
WITH_CONFIG(B_PICKUP_WILD, GEN_9);
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -31,7 +31,7 @@ SINGLE_BATTLE_TEST("Pixilate boosts power of affected moves by 20% (Gen7+) or 30
PARAMETRIZE { ability = ABILITY_PIXILATE; genConfig = GEN_6; }
GIVEN {
WITH_CONFIG(CONFIG_ATE_MULTIPLIER, genConfig);
WITH_CONFIG(B_ATE_MULTIPLIER, genConfig);
PLAYER(SPECIES_SYLVEON) { Ability(ability); Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -38,7 +38,7 @@ SINGLE_BATTLE_TEST("Poison Point triggers 1/3 times (Gen3) or 30% (Gen 4+) of th
PARAMETRIZE { config = GEN_4; passes = 3; trials = 10; } // 30%
PASSES_RANDOMLY(passes, trials, RNG_POISON_POINT);
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_TRIGGER_CHANCE, config);
WITH_CONFIG(B_ABILITY_TRIGGER_CHANCE, config);
ASSUME(MoveMakesContact(MOVE_SCRATCH));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_NIDORAN_M) { Ability(ABILITY_POISON_POINT); }

View File

@ -13,7 +13,7 @@ SINGLE_BATTLE_TEST("Prankster-affected moves don't affect Dark-type Pokémon (Ge
PARAMETRIZE { gen = GEN_6; }
PARAMETRIZE { gen = GEN_7; }
GIVEN {
WITH_CONFIG(CONFIG_PRANKSTER_DARK_TYPES, gen);
WITH_CONFIG(B_PRANKSTER_DARK_TYPES, gen);
PLAYER(SPECIES_UMBREON);
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); }
} WHEN {
@ -31,7 +31,7 @@ SINGLE_BATTLE_TEST("Prankster-affected moves don't affect Dark-type Pokémon (Ge
SINGLE_BATTLE_TEST("Prankster-affected moves don't affect Dark-type Pokémon after they switch-in")
{
GIVEN {
WITH_CONFIG(CONFIG_PRANKSTER_DARK_TYPES, GEN_7);
WITH_CONFIG(B_PRANKSTER_DARK_TYPES, GEN_7);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_UMBREON);
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); }
@ -64,7 +64,7 @@ SINGLE_BATTLE_TEST("Prankster-affected moves called via Assist don't affect Dark
PARAMETRIZE { gen = GEN_6; }
PARAMETRIZE { gen = GEN_7; }
GIVEN {
WITH_CONFIG(CONFIG_PRANKSTER_DARK_TYPES, gen);
WITH_CONFIG(B_PRANKSTER_DARK_TYPES, gen);
PLAYER(SPECIES_UMBREON);
OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CONFUSE_RAY); }
@ -87,7 +87,7 @@ DOUBLE_BATTLE_TEST("Prankster-affected moves called via Instruct do not affect D
PARAMETRIZE { gen = GEN_6; }
PARAMETRIZE { gen = GEN_7; }
GIVEN {
WITH_CONFIG(CONFIG_PRANKSTER_DARK_TYPES, gen);
WITH_CONFIG(B_PRANKSTER_DARK_TYPES, gen);
PLAYER(SPECIES_VOLBEAT) { Speed(20); Ability(ABILITY_PRANKSTER); }
PLAYER(SPECIES_WOBBUFFET) { Speed(10); }
OPPONENT(SPECIES_UMBREON) { Speed(15); }
@ -203,7 +203,7 @@ SINGLE_BATTLE_TEST("Prankster-affected moves which are reflected by Magic Coat c
PARAMETRIZE { sableyeAbility = ABILITY_KEEN_EYE; }
GIVEN {
WITH_CONFIG(CONFIG_PRANKSTER_DARK_TYPES, GEN_7);
WITH_CONFIG(B_PRANKSTER_DARK_TYPES, GEN_7);
PLAYER(SPECIES_SABLEYE) { Ability(sableyeAbility); }
OPPONENT(SPECIES_MURKROW) { Ability(ABILITY_PRANKSTER); }
} WHEN {

View File

@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Protean/Libero changes the type of the user to the move used
PARAMETRIZE { ability = ABILITY_PROTEAN; species = SPECIES_KECLEON; }
PARAMETRIZE { ability = ABILITY_LIBERO; species = SPECIES_RABOOT; }
GIVEN {
WITH_CONFIG(CONFIG_PROTEAN_LIBERO, GEN_6);
WITH_CONFIG(B_PROTEAN_LIBERO, GEN_6);
PLAYER(SPECIES_REGIROCK);
OPPONENT(species) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);
@ -45,7 +45,7 @@ SINGLE_BATTLE_TEST("Protean/Libero changes the type of the user only once per sw
PARAMETRIZE { ability = ABILITY_PROTEAN; species = SPECIES_KECLEON; }
PARAMETRIZE { ability = ABILITY_LIBERO; species = SPECIES_RABOOT; }
GIVEN {
WITH_CONFIG(CONFIG_PROTEAN_LIBERO, GEN_9);
WITH_CONFIG(B_PROTEAN_LIBERO, GEN_9);
PLAYER(SPECIES_REGIROCK);
OPPONENT(species) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -59,7 +59,7 @@ SINGLE_BATTLE_TEST("Protosynthesis ability pop up activates only once during the
u16 turns;
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_6);
PLAYER(SPECIES_WALKING_WAKE) { Ability(ABILITY_PROTOSYNTHESIS); }
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); }
} WHEN {

View File

@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Rattled boosts speed by 1 when hit by Bug, Dark or Ghost typ
SINGLE_BATTLE_TEST("Rattled does not boost speed by 1 when affected by Intimidate (Gen5-7)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_7);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_7);
PLAYER(SPECIES_GYARADOS) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_SUDOWOODO) { Ability(ABILITY_RATTLED); }
} WHEN {
@ -75,7 +75,7 @@ SINGLE_BATTLE_TEST("Rattled does not boost speed by 1 when affected by Intimidat
SINGLE_BATTLE_TEST("Rattled boosts speed by 1 when affected by Intimidate (Gen8+)")
{
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_8);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_8);
PLAYER(SPECIES_GYARADOS) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_SUDOWOODO) { Ability(ABILITY_RATTLED); }
} WHEN {

View File

@ -30,7 +30,7 @@ SINGLE_BATTLE_TEST("Refrigerate boosts power of affected moves by 20% (Gen7+) or
PARAMETRIZE { ability = ABILITY_REFRIGERATE; genConfig = GEN_6; }
GIVEN {
WITH_CONFIG(CONFIG_ATE_MULTIPLIER, genConfig);
WITH_CONFIG(B_ATE_MULTIPLIER, genConfig);
PLAYER(SPECIES_AMAURA) { Ability(ability); Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -54,7 +54,7 @@ SINGLE_BATTLE_TEST("Refrigerate doesn't affect Weather Ball's type", s16 damage)
PARAMETRIZE { move = MOVE_CELEBRATE; ability = ABILITY_REFRIGERATE; }
PARAMETRIZE { move = MOVE_SUNNY_DAY; ability = ABILITY_REFRIGERATE; }
GIVEN {
WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_9); //To prevent capturing hail damage
WITH_CONFIG(B_SNOW_WARNING, GEN_9); //To prevent capturing hail damage
ASSUME(GetMoveEffect(MOVE_WEATHER_BALL) == EFFECT_WEATHER_BALL);
ASSUME(GetSpeciesType(SPECIES_PINSIR, 0) == TYPE_BUG);
PLAYER(SPECIES_AMAURA) { Ability(ability); }

View File

@ -4,7 +4,7 @@
SINGLE_BATTLE_TEST("Sand Stream sets up sandstorm for 5 turns (Gen6+)")
{
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_6);
PLAYER(SPECIES_HIPPOWDON) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SAND_STREAM); }
OPPONENT(SPECIES_SANDSLASH) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -26,7 +26,7 @@ SINGLE_BATTLE_TEST("Sand Stream sets up sandstorm for 5 turns (Gen6+)")
SINGLE_BATTLE_TEST("Sand Stream sets up sandstorm for 8 turns with Smooth Rock (Gen6+)")
{
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_6);
PLAYER(SPECIES_HIPPOWDON) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SAND_STREAM); Item(ITEM_SMOOTH_ROCK); }
OPPONENT(SPECIES_SANDSLASH) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -54,7 +54,7 @@ SINGLE_BATTLE_TEST("Sand Stream sets up sandstorm for 8 turns with Smooth Rock (
SINGLE_BATTLE_TEST("Sand Stream sets up permanent sandstorm (Gen3-5)")
{
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_3);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_3);
PLAYER(SPECIES_HIPPOWDON) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SAND_STREAM); }
OPPONENT(SPECIES_SANDSLASH) { Moves(MOVE_CELEBRATE); }
} WHEN {

View File

@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Scrappy doesn't prevent Intimidate (Gen4-7)")
s16 turnTwoHit;
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_7);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_7);
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); }
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); }
@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Scrappy prevents Intimidate (Gen8+)")
s16 turnTwoHit;
GIVEN {
WITH_CONFIG(CONFIG_UPDATED_INTIMIDATE, GEN_8);
WITH_CONFIG(B_UPDATED_INTIMIDATE, GEN_8);
PLAYER(SPECIES_EKANS) { Ability(ABILITY_SHED_SKIN); }
PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
OPPONENT(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); }

View File

@ -10,7 +10,7 @@ SINGLE_BATTLE_TEST("Shed Skin triggers 33% (Gen3, Gen5+) or 30% (Gen 4) of the t
PASSES_RANDOMLY(passes, 100, RNG_SHED_SKIN);
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_TRIGGER_CHANCE, config);
WITH_CONFIG(B_ABILITY_TRIGGER_CHANCE, config);
ASSUME(MoveMakesContact(MOVE_SCRATCH));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ARBOK) { Status1(STATUS1_POISON); Ability(ABILITY_SHED_SKIN); }

View File

@ -4,8 +4,8 @@
SINGLE_BATTLE_TEST("Snow Warning sets up hail for 5 turns (Gen6-8)")
{
GIVEN {
WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_8);
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6);
WITH_CONFIG(B_SNOW_WARNING, GEN_8);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_6);
PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -27,8 +27,8 @@ SINGLE_BATTLE_TEST("Snow Warning sets up hail for 5 turns (Gen6-8)")
SINGLE_BATTLE_TEST("Snow Warning sets up hail for 8 turns with Icy Rock (Gen6-8)")
{
GIVEN {
WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_8);
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6);
WITH_CONFIG(B_SNOW_WARNING, GEN_8);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_6);
PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); Item(ITEM_ICY_ROCK); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -56,8 +56,8 @@ SINGLE_BATTLE_TEST("Snow Warning sets up hail for 8 turns with Icy Rock (Gen6-8)
SINGLE_BATTLE_TEST("Snow Warning sets up permanent hail (Gen4-5)")
{
GIVEN {
WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_8);
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_5);
WITH_CONFIG(B_SNOW_WARNING, GEN_8);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_5);
PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -88,8 +88,8 @@ SINGLE_BATTLE_TEST("Snow Warning sets up permanent hail (Gen4-5)")
SINGLE_BATTLE_TEST("Snow Warning sets up snow for 5 turns (Gen9+)")
{
GIVEN {
WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_9);
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_9);
WITH_CONFIG(B_SNOW_WARNING, GEN_9);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_9);
PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {
@ -111,8 +111,8 @@ SINGLE_BATTLE_TEST("Snow Warning sets up snow for 5 turns (Gen9+)")
SINGLE_BATTLE_TEST("Snow Warning sets up snow for 8 turns with Icy Rock (Gen9+)")
{
GIVEN {
WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_9);
WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_9);
WITH_CONFIG(B_SNOW_WARNING, GEN_9);
WITH_CONFIG(B_ABILITY_WEATHER, GEN_9);
PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); Item(ITEM_ICY_ROCK); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); }
} WHEN {

View File

@ -27,7 +27,7 @@ DOUBLE_BATTLE_TEST("Stalwart stops Lightning Rod and Storm Drain from redirectin
PARAMETRIZE { ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; config = GEN_4; }
PARAMETRIZE { ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
WITH_CONFIG(B_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_SPARK) == TYPE_ELECTRIC);
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_STALWART); }

View File

@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Static triggers 1/3 times (Gen3) or 30% (Gen4+) of the time"
PARAMETRIZE { config = GEN_4; passes = 3; trials = 10; } // 30%
PASSES_RANDOMLY(passes, trials, RNG_STATIC);
GIVEN {
WITH_CONFIG(CONFIG_ABILITY_TRIGGER_CHANCE, config);
WITH_CONFIG(B_ABILITY_TRIGGER_CHANCE, config);
ASSUME(MoveMakesContact(MOVE_SCRATCH));
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_PIKACHU) { Ability(ABILITY_STATIC); }

View File

@ -16,3 +16,27 @@ SINGLE_BATTLE_TEST("Sticky Hold prevents item theft")
}
}
SINGLE_BATTLE_TEST("Sticky Hold prevents Incinerate from destroying berries")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_INCINERATE); }
OPPONENT(SPECIES_GASTRODON) { Ability(ABILITY_STICKY_HOLD); Item(ITEM_CHERI_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_INCINERATE); }
} THEN {
EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].item, ITEM_CHERI_BERRY);
}
}
SINGLE_BATTLE_TEST("Sticky Hold prevents Incinerate from destroying gems")
{
GIVEN {
WITH_CONFIG(B_INCINERATE_GEMS, GEN_6);
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_INCINERATE); }
OPPONENT(SPECIES_GASTRODON) { Ability(ABILITY_STICKY_HOLD); Item(ITEM_GHOST_GEM); }
} WHEN {
TURN { MOVE(player, MOVE_INCINERATE); }
} THEN {
EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].item, ITEM_GHOST_GEM);
}
}

View File

@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Storm Drain absorbs Water-type moves and increases the Sp. A
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
WITH_CONFIG(B_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GASTRODON_EAST) { Ability(ABILITY_STORM_DRAIN); }
@ -41,7 +41,7 @@ DOUBLE_BATTLE_TEST("Storm Drain forces single-target Water-type moves to target
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_REDIRECT_ABILITY_IMMUNITY, config);
WITH_CONFIG(B_REDIRECT_ABILITY_IMMUNITY, config);
ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);

View File

@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Sturdy prevents OHKOs (Gen5+)")
PARAMETRIZE { config = GEN_4; }
PARAMETRIZE { config = GEN_5; }
GIVEN {
WITH_CONFIG(CONFIG_STURDY, config);
WITH_CONFIG(B_STURDY, config);
PLAYER(SPECIES_GEODUDE) { Ability(ABILITY_STURDY); MaxHP(100); HP(100); }
PLAYER(SPECIES_GEODUDE);
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -11,7 +11,7 @@ SINGLE_BATTLE_TEST("Super Luck increases the critical hit ratio by 1 stage")
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(GetSpeciesBaseSpeed(SPECIES_TOGEPI) == 20);
WITH_CONFIG(CONFIG_CRIT_CHANCE, genConfig);
WITH_CONFIG(B_CRIT_CHANCE, genConfig);
PLAYER(SPECIES_TOGEPI) { Ability(ABILITY_SUPER_LUCK); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

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