diff --git a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml index 7a04bf3294..55d4fada45 100644 --- a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml +++ b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml @@ -23,8 +23,9 @@ body: label: Version description: What version of pokeemerald-expansion are you using as a base? options: - - 1.5.0 (Default) + - 1.5.1 (Default) - upcoming (Edge) + - 1.5.0 - 1.4.3 - 1.4.2 - 1.4.1 diff --git a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml index ef03b5547a..8c28b39421 100644 --- a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml +++ b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml @@ -23,8 +23,9 @@ body: label: Version description: What version of pokeemerald-expansion are you using as a base? options: - - 1.5.0 (Default) + - 1.5.1 (Default) - upcoming (Edge) + - 1.5.0 - 1.4.3 - 1.4.2 - 1.4.1 diff --git a/.github/ISSUE_TEMPLATE/04_other_errors.yaml b/.github/ISSUE_TEMPLATE/04_other_errors.yaml index a1ff7e0c4f..6f11d5b9ad 100644 --- a/.github/ISSUE_TEMPLATE/04_other_errors.yaml +++ b/.github/ISSUE_TEMPLATE/04_other_errors.yaml @@ -23,8 +23,9 @@ body: label: Version description: What version of pokeemerald-expansion are you using as a base? options: - - 1.5.0 (Default) + - 1.5.1 (Default) - upcoming (Edge) + - 1.5.0 - 1.4.3 - 1.4.2 - 1.4.1 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 2b747c3294..ec6958d94e 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -432,6 +432,22 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectInfernalParade @ EFFECT_INFERNAL_PARADE .4byte BattleScript_EffectTakeHeart @ EFFECT_TAKE_HEART .4byte BattleScript_EffectAxeKick @ EFFECT_AXE_KICK + .4byte BattleScript_EffectHit @ EFFECT_COLLISION_COURSE + .4byte BattleScript_EffectSpinOut @ EFFECT_SPIN_OUT + .4byte BattleScript_EffectMakeItRain @ EFFECT_MAKE_IT_RAIN + +BattleScript_EffectMakeItRain: + setmoveeffect MOVE_EFFECT_PAYDAY + call BattleScript_EffectHit_Ret + seteffectwithchance + tryfaintmon BS_TARGET + setmoveeffect MOVE_EFFECT_SP_ATK_MINUS_1 | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN + seteffectprimary + goto BattleScript_MoveEnd + +BattleScript_EffectSpinOut:: + setmoveeffect MOVE_EFFECT_SPD_MINUS_2 | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN + goto BattleScript_EffectHit BattleScript_EffectAxeKick:: setmoveeffect MOVE_EFFECT_CONFUSION @@ -1121,24 +1137,7 @@ BattleScript_HyperspaceFuryRemoveProtect:: return BattleScript_EffectPlasmaFists: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret seteffectwithchance tryfaintmon BS_TARGET applyplasmafists @@ -1147,24 +1146,7 @@ BattleScript_EffectPlasmaFists: goto BattleScript_MoveEnd BattleScript_EffectSparklySwirl: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret tryfaintmon BS_TARGET healpartystatus waitstate @@ -1173,24 +1155,7 @@ BattleScript_EffectSparklySwirl: goto BattleScript_MoveEnd BattleScript_EffectFreezyFrost: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret tryfaintmon BS_TARGET normalisebuffs printstring STRINGID_STATCHANGESGONE @@ -1199,24 +1164,7 @@ BattleScript_EffectFreezyFrost: BattleScript_EffectSappySeed: jumpifstatus3 BS_TARGET, STATUS3_LEECHSEED, BattleScript_EffectHit - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret tryfaintmon BS_TARGET jumpifhasnohp BS_TARGET, BattleScript_MoveEnd setseeded @@ -1226,24 +1174,7 @@ BattleScript_EffectSappySeed: BattleScript_EffectBaddyBad: jumpifsideaffecting BS_ATTACKER, SIDE_STATUS_REFLECT, BattleScript_EffectHit - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret tryfaintmon BS_TARGET setreflect printfromtable gReflectLightScreenSafeguardStringIds @@ -1252,24 +1183,7 @@ BattleScript_EffectBaddyBad: BattleScript_EffectGlitzyGlow: jumpifsideaffecting BS_ATTACKER, SIDE_STATUS_LIGHTSCREEN, BattleScript_EffectHit - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret tryfaintmon BS_TARGET setlightscreen printfromtable gReflectLightScreenSafeguardStringIds @@ -1430,24 +1344,7 @@ BattleScript_NoMoveEffect: BattleScript_EffectRelicSong: setmoveeffect MOVE_EFFECT_RELIC_SONG | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret seteffectwithchance argumentstatuseffect tryfaintmon BS_TARGET @@ -2214,24 +2111,7 @@ BattleScript_EffectFinalGambit: goto BattleScript_MoveEnd BattleScript_EffectHitSwitchTarget: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret tryfaintmon BS_TARGET moveendall jumpifability BS_TARGET, ABILITY_SUCTION_CUPS, BattleScript_AbilityPreventsPhasingOut @@ -3191,24 +3071,7 @@ BattleScript_EffectThroatChop: goto BattleScript_EffectHit BattleScript_EffectHitEscape: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret jumpifmovehadnoeffect BattleScript_MoveEnd jumpifability BS_TARGET, ABILITY_GUARD_DOG, BattleScript_MoveEnd seteffectwithchance @@ -3280,6 +3143,27 @@ BattleScript_MoveEnd:: moveendall end +BattleScript_EffectHit_Ret:: + attackcanceler + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + attackstring + ppreduce + critcalc + damagecalc + adjustdamage + attackanimation + waitanimation + effectivenesssound + hitanimation BS_TARGET + waitstate + healthbarupdate BS_TARGET + datahpupdate BS_TARGET + critmessage + waitmessage B_WAIT_TIME_LONG + resultmessage + waitmessage B_WAIT_TIME_LONG + return + BattleScript_EffectNaturalGift: attackcanceler attackstring @@ -3471,24 +3355,7 @@ BattleScript_EffectPoisonHit: goto BattleScript_EffectHit BattleScript_EffectAbsorb:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_AbsorbHealBlock setdrainedhp manipulatedamage DMG_BIG_ROOT @@ -3917,24 +3784,7 @@ BattleScript_EffectFlinchHit:: BattleScript_EffectFlinchStatus: setmoveeffect MOVE_EFFECT_FLINCH - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret seteffectwithchance argumentstatuseffect tryfaintmon BS_TARGET @@ -5167,24 +5017,7 @@ BattleScript_EffectBatonPass:: BattleScript_EffectRapidSpin:: .if B_SPEED_BUFFING_RAPID_SPIN == GEN_8 - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret jumpifhalfword CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_MoveEnd setmoveeffect MOVE_EFFECT_RAPIDSPIN | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN seteffectwithchance @@ -6801,9 +6634,6 @@ BattleScript_DoSwitchOut:: hidepartystatussummary BS_ATTACKER switchinanim BS_ATTACKER, FALSE waitstate - jumpifcantreverttoprimal BattleScript_DoSwitchOut2 - call BattleScript_PrimalReversionRet -BattleScript_DoSwitchOut2: switchineffects BS_ATTACKER moveendcase MOVEEND_STATUS_IMMUNITY_ABILITIES moveendcase MOVEEND_MIRROR_MOVE @@ -7958,17 +7788,12 @@ BattleScript_WishMegaEvolution:: goto BattleScript_MegaEvolutionAfterString BattleScript_PrimalReversion:: - printstring STRINGID_EMPTYSTRING3 - waitmessage 1 - setbyte gIsCriticalHit, 0 - handleprimalreversion BS_ATTACKER, 0 - handleprimalreversion BS_ATTACKER, 1 - playanimation BS_ATTACKER, B_ANIM_PRIMAL_REVERSION - waitanimation - handleprimalreversion BS_ATTACKER, 2 - printstring STRINGID_PKMNREVERTEDTOPRIMAL - waitmessage B_WAIT_TIME_LONG - switchinabilities BS_ATTACKER + call BattleScript_PrimalReversionRet + end2 + +BattleScript_PrimalReversionRestoreAttacker:: + call BattleScript_PrimalReversionRet + copybyte gBattlerAttacker, sSAVED_BATTLER end2 BattleScript_PrimalReversionRet:: @@ -7982,6 +7807,7 @@ BattleScript_PrimalReversionRet:: handleprimalreversion BS_ATTACKER, 2 printstring STRINGID_PKMNREVERTEDTOPRIMAL waitmessage B_WAIT_TIME_LONG + switchinabilities BS_ATTACKER return BattleScript_AttackerFormChange:: @@ -9023,7 +8849,7 @@ BattleScript_BadDreams_ShowPopUp: goto BattleScript_BadDreams_DmgAfterPopUp BattleScript_BadDreams_HidePopUp: destroyabilitypopup - tryfaintmon BS_TARGET + tryfaintmon BS_TARGET goto BattleScript_BadDreamsIncrement BattleScript_TookAttack:: @@ -10301,24 +10127,7 @@ BattleScript_ExtremeEvoboostEnd:: goto BattleScript_MoveEnd BattleScript_EffectHitSetRemoveTerrain: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret setterrain BattleScript_TryFaint playanimation BS_ATTACKER, B_ANIM_RESTORE_BG printfromtable gTerrainStringIds diff --git a/data/scripts/debug.inc b/data/scripts/debug.inc index d7f486907d..64b7e1dd01 100644 --- a/data/scripts/debug.inc +++ b/data/scripts/debug.inc @@ -112,4 +112,35 @@ Debug_SaveBlock2Size:: Debug_PokemonStorageSize:: .string "{PKMN}Storage size: {STR_VAR_1}/{STR_VAR_2}.$" +Debug_HatchAnEgg:: + lockall + getpartysize + goto_if_eq VAR_RESULT, 0, Debug_HatchAnEgg_NoPokemon + special ChoosePartyMon + waitstate + goto_if_ge VAR_0x8004, PARTY_SIZE, Debug_HatchAnEgg_End + specialvar VAR_RESULT, ScriptGetPartyMonSpecies + goto_if_ne VAR_RESULT, SPECIES_EGG, DebugScript_HatchAnEgg_CantForceHatch + special EggHatch + waitstate +Debug_HatchAnEgg_End:: + releaseall + end + +Debug_HatchAnEgg_NoPokemon:: + msgbox DebugScript_HatchAnEgg_Text_EmptyParty, MSGBOX_DEFAULT + releaseall + end + +DebugScript_HatchAnEgg_CantForceHatch:: + msgbox DebugScript_HatchAnEgg_Text_NotAnEgg, MSGBOX_DEFAULT + releaseall + end + +DebugScript_HatchAnEgg_Text_EmptyParty:: + .string "You have no Pokémon nor Eggs.$" + +DebugScript_HatchAnEgg_Text_NotAnEgg:: + .string "That's not a Pokémon Egg.$" + .endif diff --git a/graphics/pokemon/abomasnow/anim_frontf.png b/graphics/pokemon/abomasnow/anim_frontf.png new file mode 100644 index 0000000000..49fdfb706a Binary files /dev/null and b/graphics/pokemon/abomasnow/anim_frontf.png differ diff --git a/graphics/pokemon/alakazam/anim_frontf.png b/graphics/pokemon/alakazam/anim_frontf.png index 123b8f9304..f7de540512 100644 Binary files a/graphics/pokemon/alakazam/anim_frontf.png and b/graphics/pokemon/alakazam/anim_frontf.png differ diff --git a/graphics/pokemon/bibarel/anim_front.png b/graphics/pokemon/bibarel/anim_front.png index f50a42ae64..2143b6996f 100644 Binary files a/graphics/pokemon/bibarel/anim_front.png and b/graphics/pokemon/bibarel/anim_front.png differ diff --git a/graphics/pokemon/bibarel/anim_frontf.png b/graphics/pokemon/bibarel/anim_frontf.png new file mode 100644 index 0000000000..a15a6b5f89 Binary files /dev/null and b/graphics/pokemon/bibarel/anim_frontf.png differ diff --git a/graphics/pokemon/bibarel/normal.pal b/graphics/pokemon/bibarel/normal.pal index 71a5f280ae..cc531ec662 100644 --- a/graphics/pokemon/bibarel/normal.pal +++ b/graphics/pokemon/bibarel/normal.pal @@ -10,7 +10,7 @@ JASC-PAL 168 144 120 192 192 176 248 248 248 -56 48 40 +98 82 57 232 64 32 176 24 16 64 56 48 diff --git a/graphics/pokemon/bidoof/anim_frontf.png b/graphics/pokemon/bidoof/anim_frontf.png index c5e7b97c11..16f873bc2d 100644 Binary files a/graphics/pokemon/bidoof/anim_frontf.png and b/graphics/pokemon/bidoof/anim_frontf.png differ diff --git a/graphics/pokemon/bidoof/backf.png b/graphics/pokemon/bidoof/backf.png index 27ec709a93..e5b18638df 100644 Binary files a/graphics/pokemon/bidoof/backf.png and b/graphics/pokemon/bidoof/backf.png differ diff --git a/graphics/pokemon/buizel/backf.png b/graphics/pokemon/buizel/backf.png new file mode 100644 index 0000000000..3d8a71f2a3 Binary files /dev/null and b/graphics/pokemon/buizel/backf.png differ diff --git a/graphics/pokemon/cacturne/anim_frontf.png b/graphics/pokemon/cacturne/anim_frontf.png new file mode 100644 index 0000000000..2dbdb47772 Binary files /dev/null and b/graphics/pokemon/cacturne/anim_frontf.png differ diff --git a/graphics/pokemon/camerupt/anim_front.png b/graphics/pokemon/camerupt/anim_front.png index 61f11f8c25..785798f764 100644 Binary files a/graphics/pokemon/camerupt/anim_front.png and b/graphics/pokemon/camerupt/anim_front.png differ diff --git a/graphics/pokemon/camerupt/anim_frontf.png b/graphics/pokemon/camerupt/anim_frontf.png new file mode 100644 index 0000000000..b746a2d187 Binary files /dev/null and b/graphics/pokemon/camerupt/anim_frontf.png differ diff --git a/graphics/pokemon/camerupt/back.png b/graphics/pokemon/camerupt/back.png index f97031b2c0..4481f8262b 100644 Binary files a/graphics/pokemon/camerupt/back.png and b/graphics/pokemon/camerupt/back.png differ diff --git a/graphics/pokemon/camerupt/backf.png b/graphics/pokemon/camerupt/backf.png new file mode 100644 index 0000000000..f97031b2c0 Binary files /dev/null and b/graphics/pokemon/camerupt/backf.png differ diff --git a/graphics/pokemon/croagunk/anim_frontf.png b/graphics/pokemon/croagunk/anim_frontf.png new file mode 100644 index 0000000000..1d0ab61e1b Binary files /dev/null and b/graphics/pokemon/croagunk/anim_frontf.png differ diff --git a/graphics/pokemon/croagunk/backf.png b/graphics/pokemon/croagunk/backf.png new file mode 100644 index 0000000000..07292925c5 Binary files /dev/null and b/graphics/pokemon/croagunk/backf.png differ diff --git a/graphics/pokemon/finneon/anim_frontf.png b/graphics/pokemon/finneon/anim_frontf.png new file mode 100644 index 0000000000..26a385af46 Binary files /dev/null and b/graphics/pokemon/finneon/anim_frontf.png differ diff --git a/graphics/pokemon/finneon/backf.png b/graphics/pokemon/finneon/backf.png new file mode 100644 index 0000000000..2e05aecb68 Binary files /dev/null and b/graphics/pokemon/finneon/backf.png differ diff --git a/graphics/pokemon/floatzel/anim_front.png b/graphics/pokemon/floatzel/anim_front.png index cc97f8baa8..e6f56514c4 100644 Binary files a/graphics/pokemon/floatzel/anim_front.png and b/graphics/pokemon/floatzel/anim_front.png differ diff --git a/graphics/pokemon/floatzel/backf.png b/graphics/pokemon/floatzel/backf.png new file mode 100644 index 0000000000..82005cbd29 Binary files /dev/null and b/graphics/pokemon/floatzel/backf.png differ diff --git a/graphics/pokemon/gulpin/anim_frontf.png b/graphics/pokemon/gulpin/anim_frontf.png new file mode 100644 index 0000000000..c8b4d13d1e Binary files /dev/null and b/graphics/pokemon/gulpin/anim_frontf.png differ diff --git a/graphics/pokemon/gulpin/backf.png b/graphics/pokemon/gulpin/backf.png new file mode 100644 index 0000000000..5d73b0d24f Binary files /dev/null and b/graphics/pokemon/gulpin/backf.png differ diff --git a/graphics/pokemon/kricketot/anim_front.png b/graphics/pokemon/kricketot/anim_front.png index 1b23ff111a..e9a485ef0c 100644 Binary files a/graphics/pokemon/kricketot/anim_front.png and b/graphics/pokemon/kricketot/anim_front.png differ diff --git a/graphics/pokemon/kricketot/anim_frontf.png b/graphics/pokemon/kricketot/anim_frontf.png index 6cc750f273..ef0ca6d879 100644 Binary files a/graphics/pokemon/kricketot/anim_frontf.png and b/graphics/pokemon/kricketot/anim_frontf.png differ diff --git a/graphics/pokemon/kricketot/backf.png b/graphics/pokemon/kricketot/backf.png index c88076a28c..effaf04f32 100644 Binary files a/graphics/pokemon/kricketot/backf.png and b/graphics/pokemon/kricketot/backf.png differ diff --git a/graphics/pokemon/kricketune/backf.png b/graphics/pokemon/kricketune/backf.png index 4f7f225d2b..b07e1451b9 100644 Binary files a/graphics/pokemon/kricketune/backf.png and b/graphics/pokemon/kricketune/backf.png differ diff --git a/graphics/pokemon/lumineon/anim_frontf.png b/graphics/pokemon/lumineon/anim_frontf.png new file mode 100644 index 0000000000..ac511018d4 Binary files /dev/null and b/graphics/pokemon/lumineon/anim_frontf.png differ diff --git a/graphics/pokemon/lumineon/backf.png b/graphics/pokemon/lumineon/backf.png new file mode 100644 index 0000000000..f94e5d1daf Binary files /dev/null and b/graphics/pokemon/lumineon/backf.png differ diff --git a/graphics/pokemon/luxio/anim_front.png b/graphics/pokemon/luxio/anim_front.png index 36368cddf4..691f23e60a 100644 Binary files a/graphics/pokemon/luxio/anim_front.png and b/graphics/pokemon/luxio/anim_front.png differ diff --git a/graphics/pokemon/luxio/anim_frontf.png b/graphics/pokemon/luxio/anim_frontf.png new file mode 100644 index 0000000000..30ec79e6cd Binary files /dev/null and b/graphics/pokemon/luxio/anim_frontf.png differ diff --git a/graphics/pokemon/luxio/backf.png b/graphics/pokemon/luxio/backf.png new file mode 100644 index 0000000000..e1b5e4bb9a Binary files /dev/null and b/graphics/pokemon/luxio/backf.png differ diff --git a/graphics/pokemon/luxray/anim_front.png b/graphics/pokemon/luxray/anim_front.png index 989470b19b..b2de7e12e6 100644 Binary files a/graphics/pokemon/luxray/anim_front.png and b/graphics/pokemon/luxray/anim_front.png differ diff --git a/graphics/pokemon/luxray/anim_frontf.png b/graphics/pokemon/luxray/anim_frontf.png new file mode 100644 index 0000000000..49d83d6b75 Binary files /dev/null and b/graphics/pokemon/luxray/anim_frontf.png differ diff --git a/graphics/pokemon/luxray/backf.png b/graphics/pokemon/luxray/backf.png new file mode 100644 index 0000000000..ce0fe29e44 Binary files /dev/null and b/graphics/pokemon/luxray/backf.png differ diff --git a/graphics/pokemon/luxray/normal.pal b/graphics/pokemon/luxray/normal.pal index 302dceb373..c81dbd3677 100644 --- a/graphics/pokemon/luxray/normal.pal +++ b/graphics/pokemon/luxray/normal.pal @@ -15,5 +15,5 @@ JASC-PAL 144 56 80 72 72 112 168 56 80 -0 0 0 +255 255 255 0 0 0 diff --git a/graphics/pokemon/milotic/anim_front.png b/graphics/pokemon/milotic/anim_front.png index 3b6b12b032..56543bff7e 100644 Binary files a/graphics/pokemon/milotic/anim_front.png and b/graphics/pokemon/milotic/anim_front.png differ diff --git a/graphics/pokemon/milotic/anim_frontf.png b/graphics/pokemon/milotic/anim_frontf.png new file mode 100644 index 0000000000..a7c8fe0c2b Binary files /dev/null and b/graphics/pokemon/milotic/anim_frontf.png differ diff --git a/graphics/pokemon/milotic/back.png b/graphics/pokemon/milotic/back.png index 77cc96ab14..98dadef06a 100644 Binary files a/graphics/pokemon/milotic/back.png and b/graphics/pokemon/milotic/back.png differ diff --git a/graphics/pokemon/milotic/backf.png b/graphics/pokemon/milotic/backf.png new file mode 100644 index 0000000000..0519c4b016 Binary files /dev/null and b/graphics/pokemon/milotic/backf.png differ diff --git a/graphics/pokemon/numel/anim_front.png b/graphics/pokemon/numel/anim_front.png index b6e95b4670..1cea61e993 100644 Binary files a/graphics/pokemon/numel/anim_front.png and b/graphics/pokemon/numel/anim_front.png differ diff --git a/graphics/pokemon/numel/anim_frontf.png b/graphics/pokemon/numel/anim_frontf.png new file mode 100644 index 0000000000..6ef4e79541 Binary files /dev/null and b/graphics/pokemon/numel/anim_frontf.png differ diff --git a/graphics/pokemon/numel/back.png b/graphics/pokemon/numel/back.png index e895fefbb0..a631f1c2a9 100644 Binary files a/graphics/pokemon/numel/back.png and b/graphics/pokemon/numel/back.png differ diff --git a/graphics/pokemon/numel/backf.png b/graphics/pokemon/numel/backf.png new file mode 100644 index 0000000000..e895fefbb0 Binary files /dev/null and b/graphics/pokemon/numel/backf.png differ diff --git a/graphics/pokemon/pachirisu/anim_frontf.png b/graphics/pokemon/pachirisu/anim_frontf.png new file mode 100644 index 0000000000..55d20e4922 Binary files /dev/null and b/graphics/pokemon/pachirisu/anim_frontf.png differ diff --git a/graphics/pokemon/relicanth/anim_front.png b/graphics/pokemon/relicanth/anim_front.png index 1ff9f7ba30..c93761ec3d 100644 Binary files a/graphics/pokemon/relicanth/anim_front.png and b/graphics/pokemon/relicanth/anim_front.png differ diff --git a/graphics/pokemon/relicanth/anim_frontf.png b/graphics/pokemon/relicanth/anim_frontf.png new file mode 100644 index 0000000000..1ff9f7ba30 Binary files /dev/null and b/graphics/pokemon/relicanth/anim_frontf.png differ diff --git a/graphics/pokemon/relicanth/backf.png b/graphics/pokemon/relicanth/backf.png new file mode 100644 index 0000000000..f900aa794f Binary files /dev/null and b/graphics/pokemon/relicanth/backf.png differ diff --git a/graphics/pokemon/roselia/anim_front.png b/graphics/pokemon/roselia/anim_front.png index 814568e648..218bac70d9 100644 Binary files a/graphics/pokemon/roselia/anim_front.png and b/graphics/pokemon/roselia/anim_front.png differ diff --git a/graphics/pokemon/roselia/anim_frontf.png b/graphics/pokemon/roselia/anim_frontf.png new file mode 100644 index 0000000000..ba9bec2764 Binary files /dev/null and b/graphics/pokemon/roselia/anim_frontf.png differ diff --git a/graphics/pokemon/roselia/backf.png b/graphics/pokemon/roselia/backf.png new file mode 100644 index 0000000000..27ff84ec68 Binary files /dev/null and b/graphics/pokemon/roselia/backf.png differ diff --git a/graphics/pokemon/roserade/anim_front.png b/graphics/pokemon/roserade/anim_front.png index e742c7a2c1..5630199f79 100644 Binary files a/graphics/pokemon/roserade/anim_front.png and b/graphics/pokemon/roserade/anim_front.png differ diff --git a/graphics/pokemon/roserade/anim_frontf.png b/graphics/pokemon/roserade/anim_frontf.png new file mode 100644 index 0000000000..b6bcee6a9b Binary files /dev/null and b/graphics/pokemon/roserade/anim_frontf.png differ diff --git a/graphics/pokemon/roserade/backf.png b/graphics/pokemon/roserade/backf.png new file mode 100644 index 0000000000..1b037aada6 Binary files /dev/null and b/graphics/pokemon/roserade/backf.png differ diff --git a/graphics/pokemon/shinx/anim_front.png b/graphics/pokemon/shinx/anim_front.png index 6f888ec4ef..064589b336 100644 Binary files a/graphics/pokemon/shinx/anim_front.png and b/graphics/pokemon/shinx/anim_front.png differ diff --git a/graphics/pokemon/shinx/anim_frontf.png b/graphics/pokemon/shinx/anim_frontf.png index 00e387be20..8ebfd688f9 100644 Binary files a/graphics/pokemon/shinx/anim_frontf.png and b/graphics/pokemon/shinx/anim_frontf.png differ diff --git a/graphics/pokemon/shinx/back.png b/graphics/pokemon/shinx/back.png index 9c89683b5b..8232bcc72c 100644 Binary files a/graphics/pokemon/shinx/back.png and b/graphics/pokemon/shinx/back.png differ diff --git a/graphics/pokemon/shinx/backf.png b/graphics/pokemon/shinx/backf.png index df82be9b30..cc02626f8a 100644 Binary files a/graphics/pokemon/shinx/backf.png and b/graphics/pokemon/shinx/backf.png differ diff --git a/graphics/pokemon/snover/anim_frontf.png b/graphics/pokemon/snover/anim_frontf.png new file mode 100644 index 0000000000..64606881f8 Binary files /dev/null and b/graphics/pokemon/snover/anim_frontf.png differ diff --git a/graphics/pokemon/snover/backf.png b/graphics/pokemon/snover/backf.png new file mode 100644 index 0000000000..8a3ed308e4 Binary files /dev/null and b/graphics/pokemon/snover/backf.png differ diff --git a/graphics/pokemon/staraptor/anim_frontf.png b/graphics/pokemon/staraptor/anim_frontf.png index 62715651bb..37e8b5cfe1 100644 Binary files a/graphics/pokemon/staraptor/anim_frontf.png and b/graphics/pokemon/staraptor/anim_frontf.png differ diff --git a/graphics/pokemon/staravia/anim_frontf.png b/graphics/pokemon/staravia/anim_frontf.png index 8658532ac7..40de79a608 100644 Binary files a/graphics/pokemon/staravia/anim_frontf.png and b/graphics/pokemon/staravia/anim_frontf.png differ diff --git a/graphics/pokemon/staravia/backf.png b/graphics/pokemon/staravia/backf.png index 36e2f2169d..51fec5992d 100644 Binary files a/graphics/pokemon/staravia/backf.png and b/graphics/pokemon/staravia/backf.png differ diff --git a/graphics/pokemon/starly/anim_front.png b/graphics/pokemon/starly/anim_front.png index 0e834f3bd3..b897ef874a 100644 Binary files a/graphics/pokemon/starly/anim_front.png and b/graphics/pokemon/starly/anim_front.png differ diff --git a/graphics/pokemon/starly/anim_frontf.png b/graphics/pokemon/starly/anim_frontf.png index 9639185e90..7209679bfa 100644 Binary files a/graphics/pokemon/starly/anim_frontf.png and b/graphics/pokemon/starly/anim_frontf.png differ diff --git a/graphics/pokemon/starly/back.png b/graphics/pokemon/starly/back.png index 17b2b70011..abea0fd5ed 100644 Binary files a/graphics/pokemon/starly/back.png and b/graphics/pokemon/starly/back.png differ diff --git a/graphics/pokemon/starly/backf.png b/graphics/pokemon/starly/backf.png index 3851350df0..f1c45a7bc6 100644 Binary files a/graphics/pokemon/starly/backf.png and b/graphics/pokemon/starly/backf.png differ diff --git a/graphics/pokemon/starly/shiny.pal b/graphics/pokemon/starly/shiny.pal index f077f79746..c49fb7aed3 100644 --- a/graphics/pokemon/starly/shiny.pal +++ b/graphics/pokemon/starly/shiny.pal @@ -4,7 +4,7 @@ JASC-PAL 152 208 160 96 64 48 16 16 16 -136 104 80 +164 115 82 56 24 24 216 200 160 248 248 248 @@ -14,6 +14,6 @@ JASC-PAL 208 152 0 192 152 128 160 112 80 -112 96 96 +139 98 74 247 82 66 0 0 0 diff --git a/graphics/pokemon/swalot/anim_frontf.png b/graphics/pokemon/swalot/anim_frontf.png new file mode 100644 index 0000000000..da17817ece Binary files /dev/null and b/graphics/pokemon/swalot/anim_frontf.png differ diff --git a/graphics/pokemon/swalot/backf.png b/graphics/pokemon/swalot/backf.png new file mode 100644 index 0000000000..fcd92c887a Binary files /dev/null and b/graphics/pokemon/swalot/backf.png differ diff --git a/graphics/pokemon/toxicroak/anim_frontf.png b/graphics/pokemon/toxicroak/anim_frontf.png new file mode 100644 index 0000000000..40f86c45ec Binary files /dev/null and b/graphics/pokemon/toxicroak/anim_frontf.png differ diff --git a/graphics/pokemon/toxicroak/backf.png b/graphics/pokemon/toxicroak/backf.png new file mode 100644 index 0000000000..dde6b0be22 Binary files /dev/null and b/graphics/pokemon/toxicroak/backf.png differ diff --git a/include/battle.h b/include/battle.h index 5acde903aa..00893d105e 100644 --- a/include/battle.h +++ b/include/battle.h @@ -634,7 +634,7 @@ struct BattleStruct bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once. u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used. u16 moveEffect2; // For Knock Off - u16 changedSpecies[PARTY_SIZE]; // For Zygarde or future forms when multiple mons can change into the same pokemon. + u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon. u8 quickClawBattlerId; struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member) u8 blunderPolicy:1; // should blunder policy activate diff --git a/include/battle_anim.h b/include/battle_anim.h index 4b5471d413..8a1e76a8a5 100644 --- a/include/battle_anim.h +++ b/include/battle_anim.h @@ -2,6 +2,7 @@ #define GUARD_BATTLE_ANIM_H #include "battle.h" +#include "constants/battle.h" #include "constants/battle_anim.h" #include "task.h" @@ -204,10 +205,10 @@ u8 GetBattlerSpriteDefault_Y(u8 battlerId); u8 GetSubstituteSpriteDefault_Y(u8 battlerId); // battle_anim_status_effects.c -#define STAT_ANIM_PLUS1 15 -#define STAT_ANIM_PLUS2 39 -#define STAT_ANIM_MINUS1 22 -#define STAT_ANIM_MINUS2 46 +#define STAT_ANIM_PLUS1 MOVE_EFFECT_ATK_PLUS_1 +#define STAT_ANIM_PLUS2 MOVE_EFFECT_ATK_PLUS_2 +#define STAT_ANIM_MINUS1 MOVE_EFFECT_ATK_MINUS_1 +#define STAT_ANIM_MINUS2 MOVE_EFFECT_ATK_MINUS_2 #define STAT_ANIM_MULTIPLE_PLUS1 55 #define STAT_ANIM_MULTIPLE_PLUS2 56 #define STAT_ANIM_MULTIPLE_MINUS1 57 diff --git a/include/battle_main.h b/include/battle_main.h index 4f20e4c17a..5f603654bc 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -72,6 +72,7 @@ bool32 IsWildMonSmart(void); u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags); void ModifyPersonalityForNature(u32 *personality, u32 newNature); u32 GeneratePersonalityForGender(u32 gender, u32 species); +void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMonCustomized *partyEntry); extern struct MultiPartnerMenuPokemon gMultiPartnerParty[MULTI_PARTY_SIZE]; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 8996abd719..f34f801399 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -418,6 +418,7 @@ extern const u8 BattleScript_AttackWeakenedByStrongWinds[]; extern const u8 BattleScript_BlockedByPrimalWeatherEnd3[]; extern const u8 BattleScript_BlockedByPrimalWeatherRet[]; extern const u8 BattleScript_PrimalReversion[]; +extern const u8 BattleScript_PrimalReversionRestoreAttacker[]; extern const u8 BattleScript_HyperspaceFuryRemoveProtect[]; extern const u8 BattleScript_SelectingNotAllowedMoveGorillaTactics[]; extern const u8 BattleScript_SelectingNotAllowedMoveGorillaTacticsInPalace[]; diff --git a/include/battle_util.h b/include/battle_util.h index 0431d7ba4c..7ae9577b74 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -142,6 +142,7 @@ u8 AtkCanceller_UnableToUseMove2(void); bool8 HasNoMonsToSwitch(u8 battlerId, u8 r1, u8 r2); bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility); u8 AbilityBattleEffects(u8 caseID, u8 battlerId, u16 ability, u8 special, u16 moveArg); +bool32 TryPrimalReversion(u8 battlerId); bool32 IsNeutralizingGasOnField(void); u32 GetBattlerAbility(u8 battlerId); u32 IsAbilityOnSide(u32 battlerId, u32 ability); @@ -208,6 +209,7 @@ void BufferStatChange(u8 battlerId, u8 statId, u8 stringId); bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef, bool32 checkTarget); u16 GetUsedHeldItem(u8 battler); bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags); +u32 ApplyWeatherDamageMultiplier(u8 battlerAtk, u16 move, u8 moveType, u32 dmg, u16 holdEffectAtk, u16 holdEffectDef); u32 GetBattlerMoveTargetType(u8 battlerId, u16 move); bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move); bool8 IsMoveAffectedByParentalBond(u16 move, u8 battlerId); diff --git a/include/config/item.h b/include/config/item.h index 1e174b5ff4..ad205f0034 100644 --- a/include/config/item.h +++ b/include/config/item.h @@ -10,6 +10,7 @@ #define I_VITAMIN_EV_CAP GEN_LATEST // In Gen8+, the Vitamins no longer have a cap of 100 EV per stat. #define I_BERRY_EV_JUMP GEN_LATEST // In Gen4 only, EV-lowering Berries lower a stat's EV to 100 if it is above 100. #define I_GRISEOUS_ORB_FORM_CHANGE GEN_LATEST // In Gen9+, the Griseous Orb no longer changes Giratina's form when held. +#define I_GEM_BOOST_POWER GEN_LATEST // In Gen5+, the Gem boost power was reduced from 50% to 30%. #define I_USE_EVO_HELD_ITEMS_FROM_BAG FALSE // If TRUE, items such as Razor Claw or Electirizer will be usable from the bag to evolve a Pokémon just like in LA. // TM config diff --git a/include/constants/battle.h b/include/constants/battle.h index c32af976c7..7f2cb164e4 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -321,21 +321,21 @@ #define MOVE_EFFECT_PAYDAY 12 #define MOVE_EFFECT_CHARGING 13 #define MOVE_EFFECT_WRAP 14 -#define MOVE_EFFECT_BURN_UP 15 // MOVE_EFFECT_BURN_UP replaces unused MOVE_EFFECT_RECOIL_25 so that stat change animations don't break -#define MOVE_EFFECT_ATK_PLUS_1 16 -#define MOVE_EFFECT_DEF_PLUS_1 17 -#define MOVE_EFFECT_SPD_PLUS_1 18 -#define MOVE_EFFECT_SP_ATK_PLUS_1 19 -#define MOVE_EFFECT_SP_DEF_PLUS_1 20 -#define MOVE_EFFECT_ACC_PLUS_1 21 -#define MOVE_EFFECT_EVS_PLUS_1 22 -#define MOVE_EFFECT_ATK_MINUS_1 23 -#define MOVE_EFFECT_DEF_MINUS_1 24 -#define MOVE_EFFECT_SPD_MINUS_1 25 -#define MOVE_EFFECT_SP_ATK_MINUS_1 26 -#define MOVE_EFFECT_SP_DEF_MINUS_1 27 -#define MOVE_EFFECT_ACC_MINUS_1 28 -#define MOVE_EFFECT_EVS_MINUS_1 29 +#define MOVE_EFFECT_ATK_PLUS_1 15 +#define MOVE_EFFECT_DEF_PLUS_1 16 +#define MOVE_EFFECT_SPD_PLUS_1 17 +#define MOVE_EFFECT_SP_ATK_PLUS_1 18 +#define MOVE_EFFECT_SP_DEF_PLUS_1 19 +#define MOVE_EFFECT_ACC_PLUS_1 20 +#define MOVE_EFFECT_EVS_PLUS_1 21 +#define MOVE_EFFECT_ATK_MINUS_1 22 +#define MOVE_EFFECT_DEF_MINUS_1 23 +#define MOVE_EFFECT_SPD_MINUS_1 24 +#define MOVE_EFFECT_SP_ATK_MINUS_1 25 +#define MOVE_EFFECT_SP_DEF_MINUS_1 26 +#define MOVE_EFFECT_ACC_MINUS_1 27 +#define MOVE_EFFECT_EVS_MINUS_1 28 +#define MOVE_EFFECT_BURN_UP 29 #define MOVE_EFFECT_RECHARGE 30 #define MOVE_EFFECT_RAGE 31 #define MOVE_EFFECT_STEAL_ITEM 32 @@ -345,21 +345,21 @@ #define MOVE_EFFECT_RAPIDSPIN 36 #define MOVE_EFFECT_REMOVE_STATUS 37 #define MOVE_EFFECT_ATK_DEF_DOWN 38 -#define MOVE_EFFECT_SCALE_SHOT 39 // MOVE_EFFECT_SCALE_SHOT replaces unused MOVE_EFFECT_RECOIL_33 so that stat change animations don't break -#define MOVE_EFFECT_ATK_PLUS_2 40 -#define MOVE_EFFECT_DEF_PLUS_2 41 -#define MOVE_EFFECT_SPD_PLUS_2 42 -#define MOVE_EFFECT_SP_ATK_PLUS_2 43 -#define MOVE_EFFECT_SP_DEF_PLUS_2 44 -#define MOVE_EFFECT_ACC_PLUS_2 45 -#define MOVE_EFFECT_EVS_PLUS_2 46 -#define MOVE_EFFECT_ATK_MINUS_2 47 -#define MOVE_EFFECT_DEF_MINUS_2 48 -#define MOVE_EFFECT_SPD_MINUS_2 49 -#define MOVE_EFFECT_SP_ATK_MINUS_2 50 -#define MOVE_EFFECT_SP_DEF_MINUS_2 51 -#define MOVE_EFFECT_ACC_MINUS_2 52 -#define MOVE_EFFECT_EVS_MINUS_2 53 +#define MOVE_EFFECT_ATK_PLUS_2 39 +#define MOVE_EFFECT_DEF_PLUS_2 40 +#define MOVE_EFFECT_SPD_PLUS_2 41 +#define MOVE_EFFECT_SP_ATK_PLUS_2 42 +#define MOVE_EFFECT_SP_DEF_PLUS_2 43 +#define MOVE_EFFECT_ACC_PLUS_2 44 +#define MOVE_EFFECT_EVS_PLUS_2 45 +#define MOVE_EFFECT_ATK_MINUS_2 46 +#define MOVE_EFFECT_DEF_MINUS_2 47 +#define MOVE_EFFECT_SPD_MINUS_2 48 +#define MOVE_EFFECT_SP_ATK_MINUS_2 49 +#define MOVE_EFFECT_SP_DEF_MINUS_2 50 +#define MOVE_EFFECT_ACC_MINUS_2 51 +#define MOVE_EFFECT_EVS_MINUS_2 52 +#define MOVE_EFFECT_SCALE_SHOT 53 #define MOVE_EFFECT_THRASH 54 #define MOVE_EFFECT_KNOCK_OFF 55 #define MOVE_EFFECT_DEF_SPDEF_DOWN 56 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index c10f6d942a..bb38d86599 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -409,7 +409,10 @@ #define EFFECT_INFERNAL_PARADE 403 #define EFFECT_TAKE_HEART 404 #define EFFECT_AXE_KICK 405 +#define EFFECT_COLLISION_COURSE 406 +#define EFFECT_SPIN_OUT 407 +#define EFFECT_MAKE_IT_RAIN 408 -#define NUM_BATTLE_MOVE_EFFECTS 406 +#define NUM_BATTLE_MOVE_EFFECTS 409 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/graphics.h b/include/graphics.h index 14c2e4c6a6..2d94fd7266 100644 --- a/include/graphics.h +++ b/include/graphics.h @@ -436,14 +436,19 @@ extern const u32 gMonFrontPic_Minun[]; extern const u32 gMonFrontPic_Volbeat[]; extern const u32 gMonFrontPic_Illumise[]; extern const u32 gMonFrontPic_Roselia[]; +extern const u32 gMonFrontPic_RoseliaF[]; extern const u32 gMonFrontPic_Gulpin[]; +extern const u32 gMonFrontPic_GulpinF[]; extern const u32 gMonFrontPic_Swalot[]; +extern const u32 gMonFrontPic_SwalotF[]; extern const u32 gMonFrontPic_Carvanha[]; extern const u32 gMonFrontPic_Sharpedo[]; extern const u32 gMonFrontPic_Wailmer[]; extern const u32 gMonFrontPic_Wailord[]; extern const u32 gMonFrontPic_Numel[]; +extern const u32 gMonFrontPic_NumelF[]; extern const u32 gMonFrontPic_Camerupt[]; +extern const u32 gMonFrontPic_CameruptF[]; extern const u32 gMonFrontPic_Torkoal[]; extern const u32 gMonFrontPic_Spoink[]; extern const u32 gMonFrontPic_Grumpig[]; @@ -453,6 +458,7 @@ extern const u32 gMonFrontPic_Vibrava[]; extern const u32 gMonFrontPic_Flygon[]; extern const u32 gMonFrontPic_Cacnea[]; extern const u32 gMonFrontPic_Cacturne[]; +extern const u32 gMonFrontPic_CacturneF[]; extern const u32 gMonFrontPic_Swablu[]; extern const u32 gMonFrontPic_Altaria[]; extern const u32 gMonFrontPic_Zangoose[]; @@ -471,6 +477,7 @@ extern const u32 gMonFrontPic_Anorith[]; extern const u32 gMonFrontPic_Armaldo[]; extern const u32 gMonFrontPic_Feebas[]; extern const u32 gMonFrontPic_Milotic[]; +extern const u32 gMonFrontPic_MiloticF[]; extern const u32 gMonFrontPic_Castform[]; extern const u32 gMonFrontPic_Kecleon[]; extern const u32 gMonFrontPic_Shuppet[]; @@ -490,6 +497,7 @@ extern const u32 gMonFrontPic_Clamperl[]; extern const u32 gMonFrontPic_Huntail[]; extern const u32 gMonFrontPic_Gorebyss[]; extern const u32 gMonFrontPic_Relicanth[]; +extern const u32 gMonFrontPic_RelicanthF[]; extern const u32 gMonFrontPic_Luvdisc[]; extern const u32 gMonFrontPic_Bagon[]; extern const u32 gMonFrontPic_Shelgon[]; @@ -526,6 +534,7 @@ extern const u32 gMonFrontPic_StaraptorF[]; extern const u32 gMonFrontPic_Bidoof[]; extern const u32 gMonFrontPic_BidoofF[]; extern const u32 gMonFrontPic_Bibarel[]; +extern const u32 gMonFrontPic_BibarelF[]; extern const u32 gMonFrontPic_Kricketot[]; extern const u32 gMonFrontPic_KricketotF[]; extern const u32 gMonFrontPic_Kricketune[]; @@ -533,9 +542,12 @@ extern const u32 gMonFrontPic_KricketuneF[]; extern const u32 gMonFrontPic_Shinx[]; extern const u32 gMonFrontPic_ShinxF[]; extern const u32 gMonFrontPic_Luxio[]; +extern const u32 gMonFrontPic_LuxioF[]; extern const u32 gMonFrontPic_Luxray[]; +extern const u32 gMonFrontPic_LuxrayF[]; extern const u32 gMonFrontPic_Budew[]; extern const u32 gMonFrontPic_Roserade[]; +extern const u32 gMonFrontPic_RoseradeF[]; extern const u32 gMonFrontPic_Cranidos[]; extern const u32 gMonFrontPic_Rampardos[]; extern const u32 gMonFrontPic_Shieldon[]; @@ -546,6 +558,7 @@ extern const u32 gMonFrontPic_Mothim[]; extern const u32 gMonFrontPic_Combee[]; extern const u32 gMonFrontPic_Vespiquen[]; extern const u32 gMonFrontPic_Pachirisu[]; +extern const u32 gMonFrontPic_PachirisuF[]; extern const u32 gMonFrontPic_Buizel[]; extern const u32 gMonFrontPic_Floatzel[]; extern const u32 gMonFrontPic_Cherubi[]; @@ -586,13 +599,19 @@ extern const u32 gMonFrontPic_Hippowdon[]; extern const u32 gMonFrontPic_Skorupi[]; extern const u32 gMonFrontPic_Drapion[]; extern const u32 gMonFrontPic_Croagunk[]; +extern const u32 gMonFrontPic_CroagunkF[]; extern const u32 gMonFrontPic_Toxicroak[]; +extern const u32 gMonFrontPic_ToxicroakF[]; extern const u32 gMonFrontPic_Carnivine[]; extern const u32 gMonFrontPic_Finneon[]; +extern const u32 gMonFrontPic_FinneonF[]; extern const u32 gMonFrontPic_Lumineon[]; +extern const u32 gMonFrontPic_LumineonF[]; extern const u32 gMonFrontPic_Mantyke[]; extern const u32 gMonFrontPic_Snover[]; +extern const u32 gMonFrontPic_SnoverF[]; extern const u32 gMonFrontPic_Abomasnow[]; +extern const u32 gMonFrontPic_AbomasnowF[]; extern const u32 gMonFrontPic_Weavile[]; extern const u32 gMonFrontPic_WeavileF[]; extern const u32 gMonFrontPic_Magnezone[]; @@ -1710,14 +1729,19 @@ extern const u32 gMonBackPic_Minun[]; extern const u32 gMonBackPic_Volbeat[]; extern const u32 gMonBackPic_Illumise[]; extern const u32 gMonBackPic_Roselia[]; +extern const u32 gMonBackPic_RoseliaF[]; extern const u32 gMonBackPic_Gulpin[]; +extern const u32 gMonBackPic_GulpinF[]; extern const u32 gMonBackPic_Swalot[]; +extern const u32 gMonBackPic_SwalotF[]; extern const u32 gMonBackPic_Carvanha[]; extern const u32 gMonBackPic_Sharpedo[]; extern const u32 gMonBackPic_Wailmer[]; extern const u32 gMonBackPic_Wailord[]; extern const u32 gMonBackPic_Numel[]; +extern const u32 gMonBackPic_NumelF[]; extern const u32 gMonBackPic_Camerupt[]; +extern const u32 gMonBackPic_CameruptF[]; extern const u32 gMonBackPic_Torkoal[]; extern const u32 gMonBackPic_Spoink[]; extern const u32 gMonBackPic_Grumpig[]; @@ -1745,6 +1769,7 @@ extern const u32 gMonBackPic_Anorith[]; extern const u32 gMonBackPic_Armaldo[]; extern const u32 gMonBackPic_Feebas[]; extern const u32 gMonBackPic_Milotic[]; +extern const u32 gMonBackPic_MiloticF[]; extern const u32 gMonBackPic_Castform[]; extern const u32 gMonBackPic_Kecleon[]; extern const u32 gMonBackPic_Shuppet[]; @@ -1764,6 +1789,7 @@ extern const u32 gMonBackPic_Clamperl[]; extern const u32 gMonBackPic_Huntail[]; extern const u32 gMonBackPic_Gorebyss[]; extern const u32 gMonBackPic_Relicanth[]; +extern const u32 gMonBackPic_RelicanthF[]; extern const u32 gMonBackPic_Luvdisc[]; extern const u32 gMonBackPic_Bagon[]; extern const u32 gMonBackPic_Shelgon[]; @@ -1806,9 +1832,12 @@ extern const u32 gMonBackPic_KricketuneF[]; extern const u32 gMonBackPic_Shinx[]; extern const u32 gMonBackPic_ShinxF[]; extern const u32 gMonBackPic_Luxio[]; +extern const u32 gMonBackPic_LuxioF[]; extern const u32 gMonBackPic_Luxray[]; +extern const u32 gMonBackPic_LuxrayF[]; extern const u32 gMonBackPic_Budew[]; extern const u32 gMonBackPic_Roserade[]; +extern const u32 gMonBackPic_RoseradeF[]; extern const u32 gMonBackPic_Cranidos[]; extern const u32 gMonBackPic_Rampardos[]; extern const u32 gMonBackPic_Shieldon[]; @@ -1820,7 +1849,9 @@ extern const u32 gMonBackPic_Combee[]; extern const u32 gMonBackPic_Vespiquen[]; extern const u32 gMonBackPic_Pachirisu[]; extern const u32 gMonBackPic_Buizel[]; +extern const u32 gMonBackPic_BuizelF[]; extern const u32 gMonBackPic_Floatzel[]; +extern const u32 gMonBackPic_FloatzelF[]; extern const u32 gMonBackPic_Cherubi[]; extern const u32 gMonBackPic_Cherrim[]; extern const u32 gMonBackPic_Shellos[]; @@ -1858,12 +1889,17 @@ extern const u32 gMonBackPic_Hippowdon[]; extern const u32 gMonBackPic_Skorupi[]; extern const u32 gMonBackPic_Drapion[]; extern const u32 gMonBackPic_Croagunk[]; +extern const u32 gMonBackPic_CroagunkF[]; extern const u32 gMonBackPic_Toxicroak[]; +extern const u32 gMonBackPic_ToxicroakF[]; extern const u32 gMonBackPic_Carnivine[]; extern const u32 gMonBackPic_Finneon[]; +extern const u32 gMonBackPic_FinneonF[]; extern const u32 gMonBackPic_Lumineon[]; +extern const u32 gMonBackPic_LumineonF[]; extern const u32 gMonBackPic_Mantyke[]; extern const u32 gMonBackPic_Snover[]; +extern const u32 gMonBackPic_SnoverF[]; extern const u32 gMonBackPic_Abomasnow[]; extern const u32 gMonBackPic_Weavile[]; extern const u32 gMonBackPic_WeavileF[]; diff --git a/include/random.h b/include/random.h index 86995e36ca..db1dea3983 100644 --- a/include/random.h +++ b/include/random.h @@ -48,6 +48,10 @@ static inline void Shuffle(void *data, size_t n, size_t size) * RandomUniform(tag, lo, hi) returns a number from lo to hi inclusive * with uniform probability. * + * RandomUniformExcept(tag, lo, hi, reject) returns a number from lo to + * hi inclusive with uniform probability, excluding those for which + * reject returns TRUE. + * * RandomElement(tag, array) returns an element in array with uniform * probability. The array must be known at compile-time (e.g. a global * const array). @@ -72,8 +76,11 @@ enum RandomTag RNG_FLAME_BODY, RNG_FORCE_RANDOM_SWITCH, RNG_FROZEN, + RNG_HITS, RNG_HOLD_EFFECT_FLINCH, RNG_INFATUATION, + RNG_LOADED_DICE, + RNG_METRONOME, RNG_PARALYSIS, RNG_POISON_POINT, RNG_RAMPAGE_TURNS, @@ -121,10 +128,12 @@ enum RandomTag }) u32 RandomUniform(enum RandomTag, u32 lo, u32 hi); +u32 RandomUniformExcept(enum RandomTag, u32 lo, u32 hi, bool32 (*reject)(u32)); u32 RandomWeightedArray(enum RandomTag, u32 sum, u32 n, const u8 *weights); const void *RandomElementArray(enum RandomTag, const void *array, size_t size, size_t count); u32 RandomUniformDefault(enum RandomTag, u32 lo, u32 hi); +u32 RandomUniformExceptDefault(enum RandomTag, u32 lo, u32 hi, bool32 (*reject)(u32)); u32 RandomWeightedArrayDefault(enum RandomTag, u32 sum, u32 n, const u8 *weights); const void *RandomElementArrayDefault(enum RandomTag, const void *array, size_t size, size_t count); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 290b713b6c..9243bacb9c 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -4389,8 +4389,9 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) break; case EFFECT_SUPERPOWER: case EFFECT_OVERHEAT: + case EFFECT_MAKE_IT_RAIN: if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) - score += 10; + score += 3; break; case EFFECT_MAGIC_COAT: if (IS_MOVE_STATUS(predictedMove) && AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH)) @@ -5197,7 +5198,6 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) case EFFECT_ROOST: case EFFECT_MEMENTO: case EFFECT_GRUDGE: - case EFFECT_OVERHEAT: score -= 2; break; default: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 66acaacfb7..66ef2f1330 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -378,6 +378,7 @@ static const u16 sIgnoredPowerfulMoveEffects[] = EFFECT_ERUPTION, EFFECT_OVERHEAT, EFFECT_MIND_BLOWN, + EFFECT_MAKE_IT_RAIN, IGNORED_MOVES_END }; diff --git a/src/battle_main.c b/src/battle_main.c index 2c191512d0..eea745356a 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -121,7 +121,6 @@ static void SpriteCB_UnusedBattleInit_Main(struct Sprite *sprite); static void TrySpecialEvolution(void); static u32 Crc32B (const u8 *data, u32 size); static u32 GeneratePartyHash(const struct Trainer *trainer, u32 i); -static void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMonCustomized *partyEntry); EWRAM_DATA u16 gBattle_BG0_X = 0; EWRAM_DATA u16 gBattle_BG0_Y = 0; @@ -1955,7 +1954,7 @@ u32 GeneratePersonalityForGender(u32 gender, u32 species) return speciesInfo->genderRatio / 2; } -static void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMonCustomized *partyEntry) +void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMonCustomized *partyEntry) { bool32 noMoveSet = TRUE; u32 j; @@ -3876,13 +3875,8 @@ static void TryDoEventsBeforeFirstTurn(void) { gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->switchInAbilitiesCounter++]; - // Primal Reversion - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_PRIMAL_ORB - && GetBattleFormChangeTargetSpecies(gBattlerAttacker, FORM_CHANGE_BATTLE_PRIMAL_REVERSION) != SPECIES_NONE) - { - BattleScriptExecute(BattleScript_PrimalReversion); + if (TryPrimalReversion(gBattlerAttacker)) return; - } if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBattlerAttacker, 0, 0, 0) != 0) return; } @@ -5454,7 +5448,8 @@ static void HandleEndTurn_FinishBattle(void) changedForm = TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE); // Clear original species field - gBattleStruct->changedSpecies[i] = SPECIES_NONE; + gBattleStruct->changedSpecies[B_SIDE_PLAYER][i] = SPECIES_NONE; + gBattleStruct->changedSpecies[B_SIDE_OPPONENT][i] = SPECIES_NONE; #if B_RECALCULATE_STATS >= GEN_5 // Recalculate the stats of every party member before the end diff --git a/src/battle_message.c b/src/battle_message.c index 622c874c63..c8f05fb9af 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -3935,6 +3935,7 @@ u8 GetCurrentPpToMaxPpState(u8 currentPp, u8 maxPp) struct TrainerSlide { u16 trainerId; + bool8 isFrontierTrainer; const u8 *msgLastSwitchIn; const u8 *msgLastLowHp; const u8 *msgFirstDown; @@ -3954,6 +3955,7 @@ static const struct TrainerSlide sTrainerSlides[] = Example: { .trainerId = TRAINER_WALLY_VR_2, + .isFrontierTrainer = FALSE, .msgLastSwitchIn = sText_AarghAlmostHadIt, .msgLastLowHp = sText_BoxIsFull, .msgFirstDown = sText_123Poof, @@ -4046,7 +4048,9 @@ u32 ShouldDoTrainerSlide(u32 battlerId, u32 which) for (i = 0; i < ARRAY_COUNT(sTrainerSlides); i++) { - if (trainerId == sTrainerSlides[i].trainerId) + if (trainerId == sTrainerSlides[i].trainerId + && (((gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && sTrainerSlides[i].isFrontierTrainer) + || (!(gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && !sTrainerSlides[i].isFrontierTrainer))) { gBattleScripting.battler = battlerId; switch (which) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 1c6a2e677b..1059967ed5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -6826,7 +6826,8 @@ static void SetDmgHazardsBattlescript(u8 battlerId, u8 multistringId) bool32 DoSwitchInAbilitiesItems(u32 battlerId) { - return (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battlerId, 0, 0, 0) + return (TryPrimalReversion(battlerId) + || AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battlerId, 0, 0, 0) || (gBattleWeather & B_WEATHER_ANY && WEATHER_HAS_EFFECT && AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, battlerId, 0, 0, 0)) || (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY && AbilityBattleEffects(ABILITYEFFECT_ON_TERRAIN, battlerId, 0, 0, 0)) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battlerId, FALSE) @@ -10434,7 +10435,7 @@ static void Cmd_various(void) { gBattleStruct->battleBondTransformed[GET_BATTLER_SIDE2(gBattlerAttacker)] |= gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]; PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].species); - gBattleStruct->changedSpecies[gBattlerPartyIndexes[gBattlerAttacker]] = gBattleMons[gBattlerAttacker].species; + gBattleStruct->changedSpecies[GET_BATTLER_SIDE2(gBattlerAttacker)][gBattlerPartyIndexes[gBattlerAttacker]] = gBattleMons[gBattlerAttacker].species; gBattleMons[gBattlerAttacker].species = SPECIES_GRENINJA_ASH; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BattleBondActivatesOnMoveEndAttacker; @@ -11971,30 +11972,14 @@ static void Cmd_setmultihitcounter(void) } else { - #if B_MULTI_HIT_CHANCE >= GEN_5 - // Based on Gen 5's odds - // 35% for 2 hits - // 35% for 3 hits - // 15% for 4 hits - // 15% for 5 hits - gMultiHitCounter = Random() % 100; - if (gMultiHitCounter < 35) - gMultiHitCounter = 2; - else if (gMultiHitCounter < 35 + 35) - gMultiHitCounter = 3; - else if (gMultiHitCounter < 35 + 35 + 15) - gMultiHitCounter = 4; - else - gMultiHitCounter = 5; - #else - // 2 and 3 hits: 37.5% - // 4 and 5 hits: 12.5% - gMultiHitCounter = Random() % 4; - if (gMultiHitCounter > 1) - gMultiHitCounter = (Random() % 4) + 2; - else - gMultiHitCounter += 2; - #endif + // WARNING: These seem to be unused, see SetRandomMultiHitCounter. + #if B_MULTI_HIT_CHANCE >= GEN_5 + // 35%: 2 hits, 35%: 3 hits, 15% 4 hits, 15% 5 hits. + gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 7, 7, 3, 3); + #else + // 37.5%: 2 hits, 37.5%: 3 hits, 12.5% 4 hits, 12.5% 5 hits. + gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 3, 3, 1, 1); + #endif } } @@ -12742,41 +12727,37 @@ static void Cmd_mimicattackcopy(void) } } +static bool32 InvalidMetronomeMove(u32 move) +{ + return gBattleMoves[move].effect == EFFECT_PLACEHOLDER + || gBattleMoves[move].metronomeBanned; +} + static void Cmd_metronome(void) { CMD_ARGS(); #if B_METRONOME_MOVES >= GEN_9 - u16 moveCount = MOVES_COUNT_GEN9; + u32 moveCount = MOVES_COUNT_GEN9; #elif B_METRONOME_MOVES >= GEN_8 - u16 moveCount = MOVES_COUNT_GEN8; + u32 moveCount = MOVES_COUNT_GEN8; #elif B_METRONOME_MOVES >= GEN_7 - u16 moveCount = MOVES_COUNT_GEN7; + u32 moveCount = MOVES_COUNT_GEN7; #elif B_METRONOME_MOVES >= GEN_6 - u16 moveCount = MOVES_COUNT_GEN6; + u32 moveCount = MOVES_COUNT_GEN6; #elif B_METRONOME_MOVES >= GEN_5 - u16 moveCount = MOVES_COUNT_GEN5; + u32 moveCount = MOVES_COUNT_GEN5; #elif B_METRONOME_MOVES >= GEN_4 - u16 moveCount = MOVES_COUNT_GEN4; + u32 moveCount = MOVES_COUNT_GEN4; #elif B_METRONOME_MOVES >= GEN_3 - u16 moveCount = MOVES_COUNT_GEN3; + u32 moveCount = MOVES_COUNT_GEN3; #endif - while (TRUE) - { - gCurrentMove = (Random() % (moveCount - 1)) + 1; - if (gBattleMoves[gCurrentMove].effect == EFFECT_PLACEHOLDER) - continue; - - if (!gBattleMoves[gCurrentMove].metronomeBanned) - { - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - SetAtkCancellerForCalledMove(); - gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; - gBattlerTarget = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); - return; - } - } + gCurrentMove = RandomUniformExcept(RNG_METRONOME, 1, moveCount - 1, InvalidMetronomeMove); + gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; + SetAtkCancellerForCalledMove(); + gBattlescriptCurrInstr = gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]; + gBattlerTarget = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); } static void Cmd_dmgtolevel(void) diff --git a/src/battle_tower.c b/src/battle_tower.c index 4923080fe4..a8794358a7 100644 --- a/src/battle_tower.c +++ b/src/battle_tower.c @@ -3119,13 +3119,8 @@ static void FillPartnerParty(u16 trainerId) CreateMon(&gPlayerParty[i + 3], partyData[i].species, partyData[i].lvl, 0, TRUE, j, otIdType, otID); SetMonData(&gPlayerParty[i + 3], MON_DATA_HELD_ITEM, &partyData[i].heldItem); + CustomTrainerPartyAssignMoves(&gPlayerParty[i+3], &partyData[i]); - // TODO: Figure out a default strategy when moves are not set, to generate a good moveset - for (j = 0; j < MAX_MON_MOVES; ++j) - { - SetMonData(&gPlayerParty[i+3], MON_DATA_MOVE1 + j, &partyData[i].moves[j]); - SetMonData(&gPlayerParty[i+3], MON_DATA_PP1 + j, &gBattleMoves[partyData[i].moves[j]].pp); - } SetMonData(&gPlayerParty[i+3], MON_DATA_IVS, &(partyData[i].iv)); if (partyData[i].ev != NULL) { @@ -3164,6 +3159,8 @@ static void FillPartnerParty(u16 trainerId) StringCopy(trainerName, gTrainers[trainerId - TRAINER_CUSTOM_PARTNER].trainerName); SetMonData(&gPlayerParty[i + 3], MON_DATA_OT_NAME, trainerName); + j = gTrainers[trainerId - TRAINER_CUSTOM_PARTNER].encounterMusic_gender >> 7; + SetMonData(&gPlayerParty[i+3], MON_DATA_OT_GENDER, &j); } } else if (trainerId == TRAINER_EREADER) diff --git a/src/battle_util.c b/src/battle_util.c index 0f1613cb9c..1170ddea75 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6040,6 +6040,27 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move return effect; } +bool32 TryPrimalReversion(u8 battlerId) +{ + if (GetBattlerHoldEffect(battlerId, FALSE) == HOLD_EFFECT_PRIMAL_ORB + && GetBattleFormChangeTargetSpecies(battlerId, FORM_CHANGE_BATTLE_PRIMAL_REVERSION) != SPECIES_NONE) + { + if (gBattlerAttacker == battlerId) + { + BattleScriptExecute(BattleScript_PrimalReversion); + } + else + { + // edge case for scenarios like a switch-in after activated eject button + gBattleScripting.savedBattler = gBattlerAttacker; + gBattlerAttacker = battlerId; + BattleScriptExecute(BattleScript_PrimalReversionRestoreAttacker); + } + return TRUE; + } + return FALSE; +} + bool32 IsNeutralizingGasBannedAbility(u32 ability) { switch (ability) @@ -8784,14 +8805,16 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe case ABILITY_PROTOSYNTHESIS: { u8 atkHighestStat = GetHighestStatId(battlerAtk); - if (gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT && (atkHighestStat == STAT_ATK || atkHighestStat == STAT_SPATK)) + if (gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT + && ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK))) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); } break; case ABILITY_QUARK_DRIVE: { u8 atkHighestStat = GetHighestStatId(battlerAtk); - if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && (atkHighestStat == STAT_ATK || atkHighestStat == STAT_SPATK)) + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN + && ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK))) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); } break; @@ -8823,16 +8846,16 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe } if (IsAbilityOnField(ABILITY_VESSEL_OF_RUIN) && atkAbility != ABILITY_VESSEL_OF_RUIN && IS_MOVE_SPECIAL(gCurrentMove)) - modifier = uq4_12_multiply(modifier, UQ_4_12(0.25)); + modifier = uq4_12_multiply(modifier, UQ_4_12(0.75)); if (IsAbilityOnField(ABILITY_SWORD_OF_RUIN) && defAbility != ABILITY_SWORD_OF_RUIN && IS_MOVE_PHYSICAL(gCurrentMove)) - modifier = uq4_12_multiply(modifier, UQ_4_12(0.25)); + modifier = uq4_12_multiply(modifier, UQ_4_12(1.25)); if (IsAbilityOnField(ABILITY_TABLETS_OF_RUIN) && atkAbility != ABILITY_TABLETS_OF_RUIN && IS_MOVE_PHYSICAL(gCurrentMove)) - modifier = uq4_12_multiply(modifier, UQ_4_12(0.25)); + modifier = uq4_12_multiply(modifier, UQ_4_12(0.75)); if (IsAbilityOnField(ABILITY_BEADS_OF_RUIN) && defAbility != ABILITY_BEADS_OF_RUIN && IS_MOVE_SPECIAL(gCurrentMove)) - modifier = uq4_12_multiply(modifier, UQ_4_12(0.25)); + modifier = uq4_12_multiply(modifier, UQ_4_12(1.25)); // attacker partner's abilities if (IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) @@ -8882,14 +8905,16 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe case ABILITY_PROTOSYNTHESIS: { u8 defHighestStat = GetHighestStatId(battlerDef); - if (gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT && (defHighestStat == STAT_DEF || defHighestStat == STAT_SPDEF)) + if (gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT + && ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF))) modifier = uq4_12_multiply(modifier, UQ_4_12(0.7)); } break; case ABILITY_QUARK_DRIVE: { u8 defHighestStat = GetHighestStatId(battlerDef); - if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && (defHighestStat == STAT_DEF || defHighestStat == STAT_SPDEF)) + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN + && ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF))) modifier = uq4_12_multiply(modifier, UQ_4_12(0.7)); } break; @@ -8933,10 +8958,6 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe #endif modifier = uq4_12_multiply(modifier, holdEffectModifier); break; - case HOLD_EFFECT_GEMS: - if (gSpecialStatuses[battlerAtk].gemBoost && gBattleMons[battlerAtk].item) - modifier = uq4_12_multiply(modifier, UQ_4_12(1.0) + sPercentToModifier[gSpecialStatuses[battlerAtk].gemParam]); - break; case HOLD_EFFECT_BUG_POWER: case HOLD_EFFECT_STEEL_POWER: case HOLD_EFFECT_GROUND_POWER: @@ -9027,6 +9048,8 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe // various effects if (gProtectStructs[battlerAtk].helpingHand) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); + if (gSpecialStatuses[battlerAtk].gemBoost) + modifier = uq4_12_multiply(modifier, UQ_4_12(1.0) + sPercentToModifier[gSpecialStatuses[battlerAtk].gemParam]); if (gStatuses3[battlerAtk] & STATUS3_CHARGED_UP && moveType == TYPE_ELECTRIC) modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); if (gStatuses3[battlerAtk] & STATUS3_ME_FIRST) @@ -9423,6 +9446,8 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move u32 defSide = GET_BATTLER_SIDE(battlerDef); uq4_12_t finalModifier = UQ_4_12(1.0); u16 itemDef = gBattleMons[battlerDef].item; + u16 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); + u16 holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); // check multiple targets in double battle if (GetMoveTargetCount(move, battlerAtk, battlerDef) >= 2) @@ -9452,28 +9477,15 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move dmg = ApplyModifier(UQ_4_12(0.5), dmg); // check frostbite - if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && !IS_MOVE_PHYSICAL(move) + if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && IS_MOVE_SPECIAL(move) #if B_BURN_FACADE_DMG >= GEN_6 && gBattleMoves[move].effect != EFFECT_FACADE #endif && abilityAtk != ABILITY_GUTS) dmg = ApplyModifier(UQ_4_12(0.5), dmg); - // check sunny/rain weather - if (IsBattlerWeatherAffected(battlerAtk, B_WEATHER_RAIN)) - { - if (moveType == TYPE_FIRE) - dmg = ApplyModifier(UQ_4_12(0.5), dmg); - else if (moveType == TYPE_WATER) - dmg = ApplyModifier(UQ_4_12(1.5), dmg); - } - else if (IsBattlerWeatherAffected(battlerAtk, B_WEATHER_SUN)) - { - if (moveType == TYPE_FIRE || gBattleMoves[move].effect == EFFECT_HYDRO_STEAM) - dmg = ApplyModifier(UQ_4_12(1.5), dmg); - else if (moveType == TYPE_WATER) - dmg = ApplyModifier(UQ_4_12(0.5), dmg); - } + // check weather + dmg = ApplyWeatherDamageMultiplier(battlerAtk, move, moveType, dmg, holdEffectAtk, holdEffectDef); // check stab if (IS_BATTLER_OF_TYPE(battlerAtk, moveType) && move != MOVE_STRUGGLE && move != MOVE_NONE) @@ -9484,6 +9496,10 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move finalModifier = uq4_12_multiply(finalModifier, UQ_4_12(1.5)); } + // Collision Course, Electro Drift + if (gBattleMoves[move].effect == EFFECT_COLLISION_COURSE && typeEffectivenessModifier >= UQ_4_12(2.0)) + finalModifier = uq4_12_multiply(finalModifier, UQ_4_12(1.3333)); + // reflect, light screen, aurora veil if (((gSideStatuses[defSide] & SIDE_STATUS_REFLECT && IS_MOVE_PHYSICAL(move)) || (gSideStatuses[defSide] & SIDE_STATUS_LIGHTSCREEN && IS_MOVE_SPECIAL(move)) @@ -9558,7 +9574,7 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move } // attacker's hold effect - switch (GetBattlerHoldEffect(battlerAtk, TRUE)) + switch (holdEffectAtk) { case HOLD_EFFECT_METRONOME: percentBoost = min((gBattleStruct->sameMoveTurns[battlerAtk] * GetBattlerHoldEffectParam(battlerAtk)), 100); @@ -9574,7 +9590,7 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move } // target's hold effect - switch (GetBattlerHoldEffect(battlerDef, TRUE)) + switch (holdEffectDef) { // berries reducing dmg case HOLD_EFFECT_RESIST_BERRY: @@ -10148,8 +10164,8 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method) if (targetSpecies != SPECIES_NONE) { // Saves the original species on the first form change for the player. - if (side == B_SIDE_PLAYER && gBattleStruct->changedSpecies[monId] == SPECIES_NONE) - gBattleStruct->changedSpecies[monId] = gBattleMons[battlerId].species; + if (gBattleStruct->changedSpecies[side][monId] == SPECIES_NONE) + gBattleStruct->changedSpecies[side][monId] = gBattleMons[battlerId].species; TryToSetBattleFormChangeMoves(&party[monId], method); SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies); @@ -10157,7 +10173,7 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method) RecalcBattlerStats(battlerId, &party[monId]); return TRUE; } - else if (gBattleStruct->changedSpecies[monId] != SPECIES_NONE) + else if (gBattleStruct->changedSpecies[side][monId] != SPECIES_NONE) { bool8 restoreSpecies = FALSE; @@ -10173,7 +10189,7 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method) { // Reverts the original species TryToSetBattleFormChangeMoves(&party[monId], method); - SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[monId]); + SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[side][monId]); RecalcBattlerStats(battlerId, &party[monId]); return TRUE; } @@ -10761,6 +10777,34 @@ bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags) return FALSE; } +// Utility Umbrella holders take normal damage from what would be rain- and sun-weakened attacks. +u32 ApplyWeatherDamageMultiplier(u8 battlerAtk, u16 move, u8 moveType, u32 dmg, u16 holdEffectAtk, u16 holdEffectDef) +{ + if (WEATHER_HAS_EFFECT) + { + if (gBattleMoves[move].effect == EFFECT_HYDRO_STEAM && (gBattleWeather & B_WEATHER_SUN) && holdEffectAtk != HOLD_EFFECT_UTILITY_UMBRELLA) + dmg = ApplyModifier(UQ_4_12(1.5), dmg); + else if (holdEffectDef != HOLD_EFFECT_UTILITY_UMBRELLA) + { + if (gBattleWeather & B_WEATHER_RAIN) + { + if (moveType == TYPE_FIRE) + dmg = ApplyModifier(UQ_4_12(0.5), dmg); + else if (moveType == TYPE_WATER) + dmg = ApplyModifier(UQ_4_12(1.5), dmg); + } + else if (gBattleWeather & B_WEATHER_SUN) + { + if (moveType == TYPE_FIRE) + dmg = ApplyModifier(UQ_4_12(1.5), dmg); + else if (moveType == TYPE_WATER) + dmg = ApplyModifier(UQ_4_12(0.5), dmg); + } + } + } + return dmg; +} + // Gets move target before redirection effects etc. are applied // Possible return values are defined in battle.h following MOVE_TARGET_SELECTED u32 GetBattlerMoveTargetType(u8 battlerId, u16 move) @@ -10785,35 +10829,19 @@ bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move) static void SetRandomMultiHitCounter() { -#if (B_MULTI_HIT_CHANCE >= GEN_5) - // Based on Gen 5's odds - // 35% for 2 hits - // 35% for 3 hits - // 15% for 4 hits - // 15% for 5 hits - gMultiHitCounter = Random() % 100; - if (gMultiHitCounter < 35) - gMultiHitCounter = 2; - else if (gMultiHitCounter < 35 + 35) - gMultiHitCounter = 3; - else if (gMultiHitCounter < 35 + 35 + 15) - gMultiHitCounter = 4; - else - gMultiHitCounter = 5; -#else - // 2 and 3 hits: 37.5% - // 4 and 5 hits: 12.5% - gMultiHitCounter = Random() % 4; - if (gMultiHitCounter > 1) - gMultiHitCounter = (Random() % 4) + 2; - else - gMultiHitCounter += 2; -#endif - - if (gMultiHitCounter < 4 && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE) + if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE) { - // If roll 4 or 5 Loaded Dice doesn't do anything. Otherwise it rolls the number of hits as 5 minus a random integer from 0 to 1 inclusive. - gMultiHitCounter = 5 - (Random() & 1); + gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 5); + } + else + { +#if B_MULTI_HIT_CHANCE >= GEN_5 + // 35%: 2 hits, 35%: 3 hits, 15% 4 hits, 15% 5 hits. + gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 7, 7, 3, 3); +#else + // 37.5%: 2 hits, 37.5%: 3 hits, 12.5% 4 hits, 12.5% 5 hits. + gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 3, 3, 1, 1); +#endif } } diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 00082d6ec4..bb1db2f7de 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -13137,7 +13137,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_SPIN_OUT] = { - .effect = EFFECT_PLACEHOLDER, // EFFECT_SPIN_OUT + .effect = EFFECT_SPIN_OUT, .power = 100, .type = TYPE_STEEL, .accuracy = 100, @@ -13371,12 +13371,12 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_MAKE_IT_RAIN] = { - .effect = EFFECT_PLACEHOLDER, // EFFECT_MAKE_IT_RAIN + .effect = EFFECT_MAKE_IT_RAIN, .power = 120, .type = TYPE_STEEL, .accuracy = 100, .pp = 5, - .secondaryEffectChance = 0, + .secondaryEffectChance = 100, .target = MOVE_TARGET_BOTH, .priority = 0, .split = SPLIT_SPECIAL, @@ -13401,7 +13401,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_COLLISION_COURSE] = { - .effect = EFFECT_PLACEHOLDER, // EFFECT_COLLISION_COURSE + .effect = EFFECT_COLLISION_COURSE, .power = 100, .type = TYPE_FIGHTING, .accuracy = 100, @@ -13417,7 +13417,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_ELECTRO_DRIFT] = { - .effect = EFFECT_PLACEHOLDER, // EFFECT_COLLISION_COURSE + .effect = EFFECT_COLLISION_COURSE, .power = 100, .type = TYPE_ELECTRIC, .accuracy = 100, diff --git a/src/data/graphics/pokemon.h b/src/data/graphics/pokemon.h index 63d65079e2..7c8afc0066 100644 --- a/src/data/graphics/pokemon.h +++ b/src/data/graphics/pokemon.h @@ -369,14 +369,19 @@ const u32 gMonFrontPic_Minun[] = INCBIN_U32("graphics/pokemon/minun/anim_front.4 const u32 gMonFrontPic_Volbeat[] = INCBIN_U32("graphics/pokemon/volbeat/anim_front.4bpp.lz"); const u32 gMonFrontPic_Illumise[] = INCBIN_U32("graphics/pokemon/illumise/anim_front.4bpp.lz"); const u32 gMonFrontPic_Roselia[] = INCBIN_U32("graphics/pokemon/roselia/anim_front.4bpp.lz"); +const u32 gMonFrontPic_RoseliaF[] = INCBIN_U32("graphics/pokemon/roselia/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Gulpin[] = INCBIN_U32("graphics/pokemon/gulpin/anim_front.4bpp.lz"); +const u32 gMonFrontPic_GulpinF[] = INCBIN_U32("graphics/pokemon/gulpin/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Swalot[] = INCBIN_U32("graphics/pokemon/swalot/anim_front.4bpp.lz"); +const u32 gMonFrontPic_SwalotF[] = INCBIN_U32("graphics/pokemon/swalot/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Carvanha[] = INCBIN_U32("graphics/pokemon/carvanha/anim_front.4bpp.lz"); const u32 gMonFrontPic_Sharpedo[] = INCBIN_U32("graphics/pokemon/sharpedo/anim_front.4bpp.lz"); const u32 gMonFrontPic_Wailmer[] = INCBIN_U32("graphics/pokemon/wailmer/anim_front.4bpp.lz"); const u32 gMonFrontPic_Wailord[] = INCBIN_U32("graphics/pokemon/wailord/anim_front.4bpp.lz"); const u32 gMonFrontPic_Numel[] = INCBIN_U32("graphics/pokemon/numel/anim_front.4bpp.lz"); +const u32 gMonFrontPic_NumelF[] = INCBIN_U32("graphics/pokemon/numel/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Camerupt[] = INCBIN_U32("graphics/pokemon/camerupt/anim_front.4bpp.lz"); +const u32 gMonFrontPic_CameruptF[] = INCBIN_U32("graphics/pokemon/camerupt/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Torkoal[] = INCBIN_U32("graphics/pokemon/torkoal/anim_front.4bpp.lz"); const u32 gMonFrontPic_Spoink[] = INCBIN_U32("graphics/pokemon/spoink/anim_front.4bpp.lz"); const u32 gMonFrontPic_Grumpig[] = INCBIN_U32("graphics/pokemon/grumpig/anim_front.4bpp.lz"); @@ -386,6 +391,7 @@ const u32 gMonFrontPic_Vibrava[] = INCBIN_U32("graphics/pokemon/vibrava/anim_fro const u32 gMonFrontPic_Flygon[] = INCBIN_U32("graphics/pokemon/flygon/anim_front.4bpp.lz"); const u32 gMonFrontPic_Cacnea[] = INCBIN_U32("graphics/pokemon/cacnea/anim_front.4bpp.lz"); const u32 gMonFrontPic_Cacturne[] = INCBIN_U32("graphics/pokemon/cacturne/anim_front.4bpp.lz"); +const u32 gMonFrontPic_CacturneF[] = INCBIN_U32("graphics/pokemon/cacturne/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Swablu[] = INCBIN_U32("graphics/pokemon/swablu/anim_front.4bpp.lz"); const u32 gMonFrontPic_Altaria[] = INCBIN_U32("graphics/pokemon/altaria/anim_front.4bpp.lz"); const u32 gMonFrontPic_Zangoose[] = INCBIN_U32("graphics/pokemon/zangoose/anim_front.4bpp.lz"); @@ -404,6 +410,7 @@ const u32 gMonFrontPic_Anorith[] = INCBIN_U32("graphics/pokemon/anorith/anim_fro const u32 gMonFrontPic_Armaldo[] = INCBIN_U32("graphics/pokemon/armaldo/anim_front.4bpp.lz"); const u32 gMonFrontPic_Feebas[] = INCBIN_U32("graphics/pokemon/feebas/anim_front.4bpp.lz"); const u32 gMonFrontPic_Milotic[] = INCBIN_U32("graphics/pokemon/milotic/anim_front.4bpp.lz"); +const u32 gMonFrontPic_MiloticF[] = INCBIN_U32("graphics/pokemon/milotic/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Castform[] = INCBIN_U32("graphics/pokemon/castform/anim_front.4bpp.lz"); const u32 gMonFrontPic_Kecleon[] = INCBIN_U32("graphics/pokemon/kecleon/anim_front.4bpp.lz"); const u32 gMonFrontPic_Shuppet[] = INCBIN_U32("graphics/pokemon/shuppet/anim_front.4bpp.lz"); @@ -423,6 +430,7 @@ const u32 gMonFrontPic_Clamperl[] = INCBIN_U32("graphics/pokemon/clamperl/anim_f const u32 gMonFrontPic_Huntail[] = INCBIN_U32("graphics/pokemon/huntail/anim_front.4bpp.lz"); const u32 gMonFrontPic_Gorebyss[] = INCBIN_U32("graphics/pokemon/gorebyss/anim_front.4bpp.lz"); const u32 gMonFrontPic_Relicanth[] = INCBIN_U32("graphics/pokemon/relicanth/anim_front.4bpp.lz"); +const u32 gMonFrontPic_RelicanthF[] = INCBIN_U32("graphics/pokemon/relicanth/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Luvdisc[] = INCBIN_U32("graphics/pokemon/luvdisc/anim_front.4bpp.lz"); const u32 gMonFrontPic_Bagon[] = INCBIN_U32("graphics/pokemon/bagon/anim_front.4bpp.lz"); const u32 gMonFrontPic_Shelgon[] = INCBIN_U32("graphics/pokemon/shelgon/anim_front.4bpp.lz"); @@ -459,6 +467,7 @@ const u32 gMonFrontPic_StaraptorF[] = INCBIN_U32("graphics/pokemon/staraptor/ani const u32 gMonFrontPic_Bidoof[] = INCBIN_U32("graphics/pokemon/bidoof/anim_front.4bpp.lz"); const u32 gMonFrontPic_BidoofF[] = INCBIN_U32("graphics/pokemon/bidoof/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Bibarel[] = INCBIN_U32("graphics/pokemon/bibarel/anim_front.4bpp.lz"); +const u32 gMonFrontPic_BibarelF[] = INCBIN_U32("graphics/pokemon/bibarel/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Kricketot[] = INCBIN_U32("graphics/pokemon/kricketot/anim_front.4bpp.lz"); const u32 gMonFrontPic_KricketotF[] = INCBIN_U32("graphics/pokemon/kricketot/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Kricketune[] = INCBIN_U32("graphics/pokemon/kricketune/anim_front.4bpp.lz"); @@ -466,9 +475,12 @@ const u32 gMonFrontPic_KricketuneF[] = INCBIN_U32("graphics/pokemon/kricketune/a const u32 gMonFrontPic_Shinx[] = INCBIN_U32("graphics/pokemon/shinx/anim_front.4bpp.lz"); const u32 gMonFrontPic_ShinxF[] = INCBIN_U32("graphics/pokemon/shinx/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Luxio[] = INCBIN_U32("graphics/pokemon/luxio/anim_front.4bpp.lz"); +const u32 gMonFrontPic_LuxioF[] = INCBIN_U32("graphics/pokemon/luxio/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Luxray[] = INCBIN_U32("graphics/pokemon/luxray/anim_front.4bpp.lz"); +const u32 gMonFrontPic_LuxrayF[] = INCBIN_U32("graphics/pokemon/luxray/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Budew[] = INCBIN_U32("graphics/pokemon/budew/anim_front.4bpp.lz"); const u32 gMonFrontPic_Roserade[] = INCBIN_U32("graphics/pokemon/roserade/anim_front.4bpp.lz"); +const u32 gMonFrontPic_RoseradeF[] = INCBIN_U32("graphics/pokemon/roserade/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Cranidos[] = INCBIN_U32("graphics/pokemon/cranidos/anim_front.4bpp.lz"); const u32 gMonFrontPic_Rampardos[] = INCBIN_U32("graphics/pokemon/rampardos/anim_front.4bpp.lz"); const u32 gMonFrontPic_Shieldon[] = INCBIN_U32("graphics/pokemon/shieldon/anim_front.4bpp.lz"); @@ -479,6 +491,7 @@ const u32 gMonFrontPic_Mothim[] = INCBIN_U32("graphics/pokemon/mothim/anim_front const u32 gMonFrontPic_Combee[] = INCBIN_U32("graphics/pokemon/combee/anim_front.4bpp.lz"); const u32 gMonFrontPic_Vespiquen[] = INCBIN_U32("graphics/pokemon/vespiquen/anim_front.4bpp.lz"); const u32 gMonFrontPic_Pachirisu[] = INCBIN_U32("graphics/pokemon/pachirisu/anim_front.4bpp.lz"); +const u32 gMonFrontPic_PachirisuF[] = INCBIN_U32("graphics/pokemon/pachirisu/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Buizel[] = INCBIN_U32("graphics/pokemon/buizel/anim_front.4bpp.lz"); const u32 gMonFrontPic_Floatzel[] = INCBIN_U32("graphics/pokemon/floatzel/anim_front.4bpp.lz"); const u32 gMonFrontPic_Cherubi[] = INCBIN_U32("graphics/pokemon/cherubi/anim_front.4bpp.lz"); @@ -519,13 +532,19 @@ const u32 gMonFrontPic_Hippowdon[] = INCBIN_U32("graphics/pokemon/hippowdon/anim const u32 gMonFrontPic_Skorupi[] = INCBIN_U32("graphics/pokemon/skorupi/anim_front.4bpp.lz"); const u32 gMonFrontPic_Drapion[] = INCBIN_U32("graphics/pokemon/drapion/anim_front.4bpp.lz"); const u32 gMonFrontPic_Croagunk[] = INCBIN_U32("graphics/pokemon/croagunk/anim_front.4bpp.lz"); +const u32 gMonFrontPic_CroagunkF[] = INCBIN_U32("graphics/pokemon/croagunk/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Toxicroak[] = INCBIN_U32("graphics/pokemon/toxicroak/anim_front.4bpp.lz"); +const u32 gMonFrontPic_ToxicroakF[] = INCBIN_U32("graphics/pokemon/toxicroak/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Carnivine[] = INCBIN_U32("graphics/pokemon/carnivine/anim_front.4bpp.lz"); const u32 gMonFrontPic_Finneon[] = INCBIN_U32("graphics/pokemon/finneon/anim_front.4bpp.lz"); +const u32 gMonFrontPic_FinneonF[] = INCBIN_U32("graphics/pokemon/finneon/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Lumineon[] = INCBIN_U32("graphics/pokemon/lumineon/anim_front.4bpp.lz"); +const u32 gMonFrontPic_LumineonF[] = INCBIN_U32("graphics/pokemon/lumineon/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Mantyke[] = INCBIN_U32("graphics/pokemon/mantyke/anim_front.4bpp.lz"); const u32 gMonFrontPic_Snover[] = INCBIN_U32("graphics/pokemon/snover/anim_front.4bpp.lz"); +const u32 gMonFrontPic_SnoverF[] = INCBIN_U32("graphics/pokemon/snover/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Abomasnow[] = INCBIN_U32("graphics/pokemon/abomasnow/anim_front.4bpp.lz"); +const u32 gMonFrontPic_AbomasnowF[] = INCBIN_U32("graphics/pokemon/abomasnow/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Weavile[] = INCBIN_U32("graphics/pokemon/weavile/anim_front.4bpp.lz"); const u32 gMonFrontPic_WeavileF[] = INCBIN_U32("graphics/pokemon/weavile/anim_frontf.4bpp.lz"); const u32 gMonFrontPic_Magnezone[] = INCBIN_U32("graphics/pokemon/magnezone/anim_front.4bpp.lz"); @@ -1641,14 +1660,19 @@ const u32 gMonBackPic_Minun[] = INCBIN_U32("graphics/pokemon/minun/back.4bpp.lz" const u32 gMonBackPic_Volbeat[] = INCBIN_U32("graphics/pokemon/volbeat/back.4bpp.lz"); const u32 gMonBackPic_Illumise[] = INCBIN_U32("graphics/pokemon/illumise/back.4bpp.lz"); const u32 gMonBackPic_Roselia[] = INCBIN_U32("graphics/pokemon/roselia/back.4bpp.lz"); +const u32 gMonBackPic_RoseliaF[] = INCBIN_U32("graphics/pokemon/roselia/backf.4bpp.lz"); const u32 gMonBackPic_Gulpin[] = INCBIN_U32("graphics/pokemon/gulpin/back.4bpp.lz"); +const u32 gMonBackPic_GulpinF[] = INCBIN_U32("graphics/pokemon/gulpin/backf.4bpp.lz"); const u32 gMonBackPic_Swalot[] = INCBIN_U32("graphics/pokemon/swalot/back.4bpp.lz"); +const u32 gMonBackPic_SwalotF[] = INCBIN_U32("graphics/pokemon/swalot/backf.4bpp.lz"); const u32 gMonBackPic_Carvanha[] = INCBIN_U32("graphics/pokemon/carvanha/back.4bpp.lz"); const u32 gMonBackPic_Sharpedo[] = INCBIN_U32("graphics/pokemon/sharpedo/back.4bpp.lz"); const u32 gMonBackPic_Wailmer[] = INCBIN_U32("graphics/pokemon/wailmer/back.4bpp.lz"); const u32 gMonBackPic_Wailord[] = INCBIN_U32("graphics/pokemon/wailord/back.4bpp.lz"); const u32 gMonBackPic_Numel[] = INCBIN_U32("graphics/pokemon/numel/back.4bpp.lz"); +const u32 gMonBackPic_NumelF[] = INCBIN_U32("graphics/pokemon/numel/backf.4bpp.lz"); const u32 gMonBackPic_Camerupt[] = INCBIN_U32("graphics/pokemon/camerupt/back.4bpp.lz"); +const u32 gMonBackPic_CameruptF[] = INCBIN_U32("graphics/pokemon/camerupt/backf.4bpp.lz"); const u32 gMonBackPic_Torkoal[] = INCBIN_U32("graphics/pokemon/torkoal/back.4bpp.lz"); const u32 gMonBackPic_Spoink[] = INCBIN_U32("graphics/pokemon/spoink/back.4bpp.lz"); const u32 gMonBackPic_Grumpig[] = INCBIN_U32("graphics/pokemon/grumpig/back.4bpp.lz"); @@ -1676,6 +1700,7 @@ const u32 gMonBackPic_Anorith[] = INCBIN_U32("graphics/pokemon/anorith/back.4bpp const u32 gMonBackPic_Armaldo[] = INCBIN_U32("graphics/pokemon/armaldo/back.4bpp.lz"); const u32 gMonBackPic_Feebas[] = INCBIN_U32("graphics/pokemon/feebas/back.4bpp.lz"); const u32 gMonBackPic_Milotic[] = INCBIN_U32("graphics/pokemon/milotic/back.4bpp.lz"); +const u32 gMonBackPic_MiloticF[] = INCBIN_U32("graphics/pokemon/milotic/backf.4bpp.lz"); const u32 gMonBackPic_Castform[] = INCBIN_U32("graphics/pokemon/castform/back.4bpp.lz"); const u32 gMonBackPic_Kecleon[] = INCBIN_U32("graphics/pokemon/kecleon/back.4bpp.lz"); const u32 gMonBackPic_Shuppet[] = INCBIN_U32("graphics/pokemon/shuppet/back.4bpp.lz"); @@ -1695,6 +1720,7 @@ const u32 gMonBackPic_Clamperl[] = INCBIN_U32("graphics/pokemon/clamperl/back.4b const u32 gMonBackPic_Huntail[] = INCBIN_U32("graphics/pokemon/huntail/back.4bpp.lz"); const u32 gMonBackPic_Gorebyss[] = INCBIN_U32("graphics/pokemon/gorebyss/back.4bpp.lz"); const u32 gMonBackPic_Relicanth[] = INCBIN_U32("graphics/pokemon/relicanth/back.4bpp.lz"); +const u32 gMonBackPic_RelicanthF[] = INCBIN_U32("graphics/pokemon/relicanth/backf.4bpp.lz"); const u32 gMonBackPic_Luvdisc[] = INCBIN_U32("graphics/pokemon/luvdisc/back.4bpp.lz"); const u32 gMonBackPic_Bagon[] = INCBIN_U32("graphics/pokemon/bagon/back.4bpp.lz"); const u32 gMonBackPic_Shelgon[] = INCBIN_U32("graphics/pokemon/shelgon/back.4bpp.lz"); @@ -1737,9 +1763,12 @@ const u32 gMonBackPic_KricketuneF[] = INCBIN_U32("graphics/pokemon/kricketune/ba const u32 gMonBackPic_Shinx[] = INCBIN_U32("graphics/pokemon/shinx/back.4bpp.lz"); const u32 gMonBackPic_ShinxF[] = INCBIN_U32("graphics/pokemon/shinx/backf.4bpp.lz"); const u32 gMonBackPic_Luxio[] = INCBIN_U32("graphics/pokemon/luxio/back.4bpp.lz"); +const u32 gMonBackPic_LuxioF[] = INCBIN_U32("graphics/pokemon/luxio/backf.4bpp.lz"); const u32 gMonBackPic_Luxray[] = INCBIN_U32("graphics/pokemon/luxray/back.4bpp.lz"); +const u32 gMonBackPic_LuxrayF[] = INCBIN_U32("graphics/pokemon/luxray/backf.4bpp.lz"); const u32 gMonBackPic_Budew[] = INCBIN_U32("graphics/pokemon/budew/back.4bpp.lz"); const u32 gMonBackPic_Roserade[] = INCBIN_U32("graphics/pokemon/roserade/back.4bpp.lz"); +const u32 gMonBackPic_RoseradeF[] = INCBIN_U32("graphics/pokemon/roserade/backf.4bpp.lz"); const u32 gMonBackPic_Cranidos[] = INCBIN_U32("graphics/pokemon/cranidos/back.4bpp.lz"); const u32 gMonBackPic_Rampardos[] = INCBIN_U32("graphics/pokemon/rampardos/back.4bpp.lz"); const u32 gMonBackPic_Shieldon[] = INCBIN_U32("graphics/pokemon/shieldon/back.4bpp.lz"); @@ -1751,7 +1780,9 @@ const u32 gMonBackPic_Combee[] = INCBIN_U32("graphics/pokemon/combee/back.4bpp.l const u32 gMonBackPic_Vespiquen[] = INCBIN_U32("graphics/pokemon/vespiquen/back.4bpp.lz"); const u32 gMonBackPic_Pachirisu[] = INCBIN_U32("graphics/pokemon/pachirisu/back.4bpp.lz"); const u32 gMonBackPic_Buizel[] = INCBIN_U32("graphics/pokemon/buizel/back.4bpp.lz"); +const u32 gMonBackPic_BuizelF[] = INCBIN_U32("graphics/pokemon/buizel/backf.4bpp.lz"); const u32 gMonBackPic_Floatzel[] = INCBIN_U32("graphics/pokemon/floatzel/back.4bpp.lz"); +const u32 gMonBackPic_FloatzelF[] = INCBIN_U32("graphics/pokemon/floatzel/backf.4bpp.lz"); const u32 gMonBackPic_Cherubi[] = INCBIN_U32("graphics/pokemon/cherubi/back.4bpp.lz"); const u32 gMonBackPic_Cherrim[] = INCBIN_U32("graphics/pokemon/cherrim/normal/back.4bpp.lz"); const u32 gMonBackPic_Shellos[] = INCBIN_U32("graphics/pokemon/shellos/back.4bpp.lz"); @@ -1789,12 +1820,17 @@ const u32 gMonBackPic_Hippowdon[] = INCBIN_U32("graphics/pokemon/hippowdon/back. const u32 gMonBackPic_Skorupi[] = INCBIN_U32("graphics/pokemon/skorupi/back.4bpp.lz"); const u32 gMonBackPic_Drapion[] = INCBIN_U32("graphics/pokemon/drapion/back.4bpp.lz"); const u32 gMonBackPic_Croagunk[] = INCBIN_U32("graphics/pokemon/croagunk/back.4bpp.lz"); +const u32 gMonBackPic_CroagunkF[] = INCBIN_U32("graphics/pokemon/croagunk/backf.4bpp.lz"); const u32 gMonBackPic_Toxicroak[] = INCBIN_U32("graphics/pokemon/toxicroak/back.4bpp.lz"); +const u32 gMonBackPic_ToxicroakF[] = INCBIN_U32("graphics/pokemon/toxicroak/backf.4bpp.lz"); const u32 gMonBackPic_Carnivine[] = INCBIN_U32("graphics/pokemon/carnivine/back.4bpp.lz"); const u32 gMonBackPic_Finneon[] = INCBIN_U32("graphics/pokemon/finneon/back.4bpp.lz"); +const u32 gMonBackPic_FinneonF[] = INCBIN_U32("graphics/pokemon/finneon/backf.4bpp.lz"); const u32 gMonBackPic_Lumineon[] = INCBIN_U32("graphics/pokemon/lumineon/back.4bpp.lz"); +const u32 gMonBackPic_LumineonF[] = INCBIN_U32("graphics/pokemon/lumineon/backf.4bpp.lz"); const u32 gMonBackPic_Mantyke[] = INCBIN_U32("graphics/pokemon/mantyke/back.4bpp.lz"); const u32 gMonBackPic_Snover[] = INCBIN_U32("graphics/pokemon/snover/back.4bpp.lz"); +const u32 gMonBackPic_SnoverF[] = INCBIN_U32("graphics/pokemon/snover/backf.4bpp.lz"); const u32 gMonBackPic_Abomasnow[] = INCBIN_U32("graphics/pokemon/abomasnow/back.4bpp.lz"); const u32 gMonBackPic_Weavile[] = INCBIN_U32("graphics/pokemon/weavile/back.4bpp.lz"); const u32 gMonBackPic_WeavileF[] = INCBIN_U32("graphics/pokemon/weavile/backf.4bpp.lz"); diff --git a/src/data/items.h b/src/data/items.h index a309925aad..802cd325da 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -6,6 +6,12 @@ #define EVO_HELD_ITEM_FIELD_FUNC ItemUseOutOfBattle_CannotUse #endif +#if I_GEM_BOOST_POWER >= GEN_5 + #define GEM_BOOST_PARAM 30 +#else + #define GEM_BOOST_PARAM 50 +#endif + const struct Item gItems[] = { [ITEM_NONE] = @@ -4416,7 +4422,7 @@ const struct Item gItems[] = .itemId = ITEM_NORMAL_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sNormalGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4430,7 +4436,7 @@ const struct Item gItems[] = .itemId = ITEM_FIRE_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sFireGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4444,7 +4450,7 @@ const struct Item gItems[] = .itemId = ITEM_WATER_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sWaterGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4458,7 +4464,7 @@ const struct Item gItems[] = .itemId = ITEM_ELECTRIC_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sElectricGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4472,7 +4478,7 @@ const struct Item gItems[] = .itemId = ITEM_GRASS_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sGrassGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4486,7 +4492,7 @@ const struct Item gItems[] = .itemId = ITEM_ICE_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sIceGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4500,7 +4506,7 @@ const struct Item gItems[] = .itemId = ITEM_FIGHTING_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sFightingGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4514,7 +4520,7 @@ const struct Item gItems[] = .itemId = ITEM_POISON_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sPoisonGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4528,7 +4534,7 @@ const struct Item gItems[] = .itemId = ITEM_GROUND_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sGroundGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4542,7 +4548,7 @@ const struct Item gItems[] = .itemId = ITEM_FLYING_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sFlyingGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4556,7 +4562,7 @@ const struct Item gItems[] = .itemId = ITEM_PSYCHIC_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sPsychicGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4570,7 +4576,7 @@ const struct Item gItems[] = .itemId = ITEM_BUG_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sBugGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4584,7 +4590,7 @@ const struct Item gItems[] = .itemId = ITEM_ROCK_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sRockGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4598,7 +4604,7 @@ const struct Item gItems[] = .itemId = ITEM_GHOST_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sGhostGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4612,7 +4618,7 @@ const struct Item gItems[] = .itemId = ITEM_DRAGON_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sDragonGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4626,7 +4632,7 @@ const struct Item gItems[] = .itemId = ITEM_DARK_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sDarkGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4640,7 +4646,7 @@ const struct Item gItems[] = .itemId = ITEM_STEEL_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sSteelGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, @@ -4654,7 +4660,7 @@ const struct Item gItems[] = .itemId = ITEM_FAIRY_GEM, .price = 4000, .holdEffect = HOLD_EFFECT_GEMS, - .holdEffectParam = 30, + .holdEffectParam = GEM_BOOST_PARAM, .description = sFairyGemDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, diff --git a/src/data/pokemon_graphics/back_pic_coordinates.h b/src/data/pokemon_graphics/back_pic_coordinates.h index c849eaf2f2..d967a50fca 100644 --- a/src/data/pokemon_graphics/back_pic_coordinates.h +++ b/src/data/pokemon_graphics/back_pic_coordinates.h @@ -480,7 +480,7 @@ const struct MonCoords gMonBackPicCoords[NUM_SPECIES + 1] = [SPECIES_CROAGUNK] = { .size = MON_COORDS_SIZE(56, 56), .y_offset = 6 }, [SPECIES_TOXICROAK] = { .size = MON_COORDS_SIZE(56, 56), .y_offset = 6 }, [SPECIES_CARNIVINE] = { .size = MON_COORDS_SIZE(64, 56), .y_offset = 6 }, - [SPECIES_FINNEON] = { .size = MON_COORDS_SIZE(56, 40), .y_offset = 13 }, + [SPECIES_FINNEON] = { .size = MON_COORDS_SIZE(56, 40), .y_offset = 12 }, [SPECIES_LUMINEON] = { .size = MON_COORDS_SIZE(56, 64), .y_offset = 0 }, [SPECIES_MANTYKE] = { .size = MON_COORDS_SIZE(64, 56), .y_offset = 6 }, [SPECIES_SNOVER] = { .size = MON_COORDS_SIZE(64, 56), .y_offset = 6 }, diff --git a/src/data/pokemon_graphics/back_pic_table.h b/src/data/pokemon_graphics/back_pic_table.h index 7ade799523..a232abb567 100644 --- a/src/data/pokemon_graphics/back_pic_table.h +++ b/src/data/pokemon_graphics/back_pic_table.h @@ -1345,7 +1345,6 @@ const struct CompressedSpriteSheet gMonBackPicTableFemale[NUM_SPECIES + 1] = SPECIES_SPRITE(RATTATA, gMonBackPic_RattataF), SPECIES_SPRITE(RATICATE, gMonBackPic_RaticateF), SPECIES_SPRITE(PIKACHU, gMonBackPic_PikachuF), - SPECIES_SPRITE(RAICHU, gMonBackPic_Raichu), SPECIES_SPRITE(ZUBAT, gMonBackPic_ZubatF), SPECIES_SPRITE(GOLBAT, gMonBackPic_GolbatF), SPECIES_SPRITE(GLOOM, gMonBackPic_GloomF), @@ -1359,14 +1358,12 @@ const struct CompressedSpriteSheet gMonBackPicTableFemale[NUM_SPECIES + 1] = SPECIES_SPRITE(RHYDON, gMonBackPic_RhydonF), SPECIES_SPRITE(GOLDEEN, gMonBackPic_GoldeenF), SPECIES_SPRITE(SEAKING, gMonBackPic_SeakingF), - SPECIES_SPRITE(SCYTHER, gMonBackPic_Scyther), SPECIES_SPRITE(MAGIKARP, gMonBackPic_MagikarpF), SPECIES_SPRITE(GYARADOS, gMonBackPic_GyaradosF), SPECIES_SPRITE(EEVEE, gMonBackPic_EeveeF), SPECIES_SPRITE(MEGANIUM, gMonBackPic_MeganiumF), SPECIES_SPRITE(LEDYBA, gMonBackPic_LedybaF), SPECIES_SPRITE(LEDIAN, gMonBackPic_LedianF), - SPECIES_SPRITE(XATU, gMonBackPic_Xatu), SPECIES_SPRITE(SUDOWOODO, gMonBackPic_SudowoodoF), SPECIES_SPRITE(POLITOED, gMonBackPic_PolitoedF), SPECIES_SPRITE(AIPOM, gMonBackPic_AipomF), @@ -1377,7 +1374,6 @@ const struct CompressedSpriteSheet gMonBackPicTableFemale[NUM_SPECIES + 1] = SPECIES_SPRITE(GIRAFARIG, gMonBackPic_GirafarigF), SPECIES_SPRITE(GLIGAR, gMonBackPic_GligarF), SPECIES_SPRITE(STEELIX, gMonBackPic_SteelixF), - SPECIES_SPRITE(SCIZOR, gMonBackPic_Scizor), SPECIES_SPRITE(HERACROSS, gMonBackPic_HeracrossF), SPECIES_SPRITE(SNEASEL, gMonBackPic_SneaselF), SPECIES_SPRITE(URSARING, gMonBackPic_UrsaringF), @@ -1395,6 +1391,13 @@ const struct CompressedSpriteSheet gMonBackPicTableFemale[NUM_SPECIES + 1] = SPECIES_SPRITE(SHIFTRY, gMonBackPic_ShiftryF), SPECIES_SPRITE(MEDITITE, gMonBackPic_MedititeF), SPECIES_SPRITE(MEDICHAM, gMonBackPic_MedichamF), + SPECIES_SPRITE(ROSELIA, gMonBackPic_RoseliaF), + SPECIES_SPRITE(GULPIN, gMonBackPic_GulpinF), + SPECIES_SPRITE(SWALOT, gMonBackPic_SwalotF), + SPECIES_SPRITE(NUMEL, gMonBackPic_NumelF), + SPECIES_SPRITE(CAMERUPT, gMonBackPic_CameruptF), + SPECIES_SPRITE(MILOTIC, gMonBackPic_MiloticF), + SPECIES_SPRITE(RELICANTH, gMonBackPic_RelicanthF), #if P_GEN_4_POKEMON == TRUE SPECIES_SPRITE(STARLY, gMonBackPic_StarlyF), @@ -1404,17 +1407,21 @@ const struct CompressedSpriteSheet gMonBackPicTableFemale[NUM_SPECIES + 1] = SPECIES_SPRITE(KRICKETOT, gMonBackPic_KricketotF), SPECIES_SPRITE(KRICKETUNE, gMonBackPic_KricketuneF), SPECIES_SPRITE(SHINX, gMonBackPic_ShinxF), - SPECIES_SPRITE(COMBEE, gMonBackPic_Combee), + SPECIES_SPRITE(LUXIO, gMonBackPic_LuxioF), + SPECIES_SPRITE(LUXRAY, gMonBackPic_LuxrayF), + SPECIES_SPRITE(ROSERADE, gMonBackPic_RoseradeF), + SPECIES_SPRITE(BUIZEL, gMonBackPic_BuizelF), + SPECIES_SPRITE(FLOATZEL, gMonBackPic_FloatzelF), SPECIES_SPRITE(AMBIPOM, gMonBackPic_AmbipomF), SPECIES_SPRITE(GIBLE, gMonBackPic_GibleF), SPECIES_SPRITE(GABITE, gMonBackPic_GabiteF), - SPECIES_SPRITE(GARCHOMP, gMonBackPic_Garchomp), - SPECIES_SPRITE(HIPPOPOTAS, gMonBackPic_Hippopotas), - SPECIES_SPRITE(HIPPOWDON, gMonBackPic_Hippowdon), + SPECIES_SPRITE(CROAGUNK, gMonBackPic_CroagunkF), + SPECIES_SPRITE(TOXICROAK, gMonBackPic_ToxicroakF), + SPECIES_SPRITE(FINNEON, gMonBackPic_FinneonF), + SPECIES_SPRITE(LUMINEON, gMonBackPic_LumineonF), + SPECIES_SPRITE(SNOVER, gMonBackPic_SnoverF), SPECIES_SPRITE(WEAVILE, gMonBackPic_WeavileF), SPECIES_SPRITE(RHYPERIOR, gMonBackPic_RhyperiorF), - SPECIES_SPRITE(TANGROWTH, gMonBackPic_Tangrowth), - SPECIES_SPRITE(MAMOSWINE, gMonBackPic_Mamoswine), #endif #if P_GEN_5_POKEMON == TRUE SPECIES_SPRITE(UNFEZANT, gMonBackPic_UnfezantF), diff --git a/src/data/pokemon_graphics/front_pic_table.h b/src/data/pokemon_graphics/front_pic_table.h index 8ef0d34c36..27fefa9507 100644 --- a/src/data/pokemon_graphics/front_pic_table.h +++ b/src/data/pokemon_graphics/front_pic_table.h @@ -1384,7 +1384,6 @@ const struct CompressedSpriteSheet gMonFrontPicTableFemale[NUM_SPECIES + 1] = SPECIES_SPRITE(OCTILLERY, gMonFrontPic_OctilleryF), SPECIES_SPRITE(HOUNDOOM, gMonFrontPic_HoundoomF), SPECIES_SPRITE(DONPHAN, gMonFrontPic_DonphanF), - SPECIES_SPRITE(TORCHIC, gMonFrontPic_Torchic), SPECIES_SPRITE(COMBUSKEN, gMonFrontPic_CombuskenF), SPECIES_SPRITE(BLAZIKEN, gMonFrontPic_BlazikenF), SPECIES_SPRITE(BEAUTIFLY, gMonFrontPic_BeautiflyF), @@ -1394,18 +1393,37 @@ const struct CompressedSpriteSheet gMonFrontPicTableFemale[NUM_SPECIES + 1] = SPECIES_SPRITE(SHIFTRY, gMonFrontPic_ShiftryF), SPECIES_SPRITE(MEDITITE, gMonFrontPic_MedititeF), SPECIES_SPRITE(MEDICHAM, gMonFrontPic_MedichamF), + SPECIES_SPRITE(ROSELIA, gMonFrontPic_RoseliaF), + SPECIES_SPRITE(GULPIN, gMonFrontPic_GulpinF), + SPECIES_SPRITE(SWALOT, gMonFrontPic_SwalotF), + SPECIES_SPRITE(NUMEL, gMonFrontPic_NumelF), + SPECIES_SPRITE(CAMERUPT, gMonFrontPic_CameruptF), + SPECIES_SPRITE(CACTURNE, gMonFrontPic_CacturneF), + SPECIES_SPRITE(MILOTIC, gMonFrontPic_MiloticF), + SPECIES_SPRITE(RELICANTH, gMonFrontPic_RelicanthF), #if P_GEN_4_POKEMON == TRUE SPECIES_SPRITE(STARLY, gMonFrontPic_StarlyF), SPECIES_SPRITE(STARAVIA, gMonFrontPic_StaraviaF), SPECIES_SPRITE(STARAPTOR, gMonFrontPic_StaraptorF), SPECIES_SPRITE(BIDOOF, gMonFrontPic_BidoofF), + SPECIES_SPRITE(BIBAREL, gMonFrontPic_BibarelF), SPECIES_SPRITE(KRICKETOT, gMonFrontPic_KricketotF), SPECIES_SPRITE(KRICKETUNE, gMonFrontPic_KricketuneF), SPECIES_SPRITE(SHINX, gMonFrontPic_ShinxF), + SPECIES_SPRITE(LUXIO, gMonFrontPic_LuxioF), + SPECIES_SPRITE(LUXRAY, gMonFrontPic_LuxrayF), + SPECIES_SPRITE(ROSERADE, gMonFrontPic_RoseradeF), SPECIES_SPRITE(AMBIPOM, gMonFrontPic_AmbipomF), + SPECIES_SPRITE(PACHIRISU, gMonFrontPic_PachirisuF), SPECIES_SPRITE(GIBLE, gMonFrontPic_GibleF), SPECIES_SPRITE(GABITE, gMonFrontPic_GabiteF), SPECIES_SPRITE(GARCHOMP, gMonFrontPic_GarchompF), + SPECIES_SPRITE(CROAGUNK, gMonFrontPic_CroagunkF), + SPECIES_SPRITE(TOXICROAK, gMonFrontPic_ToxicroakF), + SPECIES_SPRITE(FINNEON, gMonFrontPic_FinneonF), + SPECIES_SPRITE(LUMINEON, gMonFrontPic_LumineonF), + SPECIES_SPRITE(SNOVER, gMonFrontPic_SnoverF), + SPECIES_SPRITE(ABOMASNOW, gMonFrontPic_AbomasnowF), SPECIES_SPRITE(WEAVILE, gMonFrontPic_WeavileF), SPECIES_SPRITE(RHYPERIOR, gMonFrontPic_RhyperiorF), SPECIES_SPRITE(TANGROWTH, gMonFrontPic_TangrowthF), diff --git a/src/debug.c b/src/debug.c index ffacba9daf..a46122baba 100644 --- a/src/debug.c +++ b/src/debug.c @@ -91,6 +91,7 @@ enum { // Util DEBUG_UTIL_MENU_ITEM_TRAINER_ID, DEBUG_UTIL_MENU_ITEM_CLEAR_BOXES, DEBUG_UTIL_MENU_ITEM_CHEAT, + DEBUG_UTIL_MENU_ITEM_HATCH_AN_EGG, }; enum { // Scripts DEBUG_UTIL_MENU_ITEM_SCRIPT_1, @@ -211,6 +212,8 @@ enum { //Sound #define DEBUG_NUMBER_ICON_X 210 #define DEBUG_NUMBER_ICON_Y 50 +#define DEBUG_MAX_MENU_ITEMS 50 + // ******************************* struct DebugMonData { @@ -234,7 +237,7 @@ struct DebugMonData struct DebugMenuListData { struct ListMenuItem listItems[20 + 1]; - u8 itemNames[PC_ITEMS_COUNT + 1][26]; + u8 itemNames[DEBUG_MAX_MENU_ITEMS + 1][26]; u8 listId; }; @@ -312,6 +315,7 @@ static void DebugAction_Util_Trainer_Gender(u8 taskId); static void DebugAction_Util_Trainer_Id(u8 taskId); static void DebugAction_Util_Clear_Boxes(u8 taskId); static void DebugAction_Util_CheatStart(u8 taskId); +static void DebugAction_Util_HatchAnEgg(u8 taskId); static void DebugAction_FlagsVars_Flags(u8 taskId); static void DebugAction_FlagsVars_FlagsSelect(u8 taskId); @@ -381,6 +385,7 @@ extern u8 Debug_Script_8[]; extern u8 Debug_ShowFieldMessageStringVar4[]; extern u8 Debug_CheatStart[]; +extern u8 Debug_HatchAnEgg[]; extern u8 PlayersHouse_2F_EventScript_SetWallClock[]; extern u8 PlayersHouse_2F_EventScript_CheckWallClock[]; extern u8 Debug_CheckSaveBlock[]; @@ -436,6 +441,7 @@ static const u8 sDebugText_Util_Trainer_Gender[] = _("Toggle T. Gender" static const u8 sDebugText_Util_Trainer_Id[] = _("New Trainer Id"); static const u8 sDebugText_Util_Clear_Boxes[] = _("Clear Storage Boxes"); static const u8 sDebugText_Util_CheatStart[] = _("CHEAT Start"); +static const u8 sDebugText_Util_HatchAnEgg[] = _("Hatch an Egg"); // Flags/Vars Menu static const u8 sDebugText_FlagsVars_Flags[] = _("Set Flag XYZ…{CLEAR_TO 110}{RIGHT_ARROW}"); static const u8 sDebugText_FlagsVars_Flag[] = _("Flag: {STR_VAR_1}{CLEAR_TO 90}\n{STR_VAR_2}{CLEAR_TO 90}\n{STR_VAR_3}"); @@ -597,6 +603,7 @@ static const struct ListMenuItem sDebugMenu_Items_Utilities[] = [DEBUG_UTIL_MENU_ITEM_TRAINER_ID] = {sDebugText_Util_Trainer_Id, DEBUG_UTIL_MENU_ITEM_TRAINER_ID}, [DEBUG_UTIL_MENU_ITEM_CLEAR_BOXES] = {sDebugText_Util_Clear_Boxes, DEBUG_UTIL_MENU_ITEM_CLEAR_BOXES}, [DEBUG_UTIL_MENU_ITEM_CHEAT] = {sDebugText_Util_CheatStart, DEBUG_UTIL_MENU_ITEM_CHEAT}, + [DEBUG_UTIL_MENU_ITEM_HATCH_AN_EGG] = {sDebugText_Util_HatchAnEgg, DEBUG_UTIL_MENU_ITEM_HATCH_AN_EGG}, }; static const struct ListMenuItem sDebugMenu_Items_Scripts[] = { @@ -729,6 +736,7 @@ static void (*const sDebugMenu_Actions_Utilities[])(u8) = [DEBUG_UTIL_MENU_ITEM_TRAINER_ID] = DebugAction_Util_Trainer_Id, [DEBUG_UTIL_MENU_ITEM_CLEAR_BOXES] = DebugAction_Util_Clear_Boxes, [DEBUG_UTIL_MENU_ITEM_CHEAT] = DebugAction_Util_CheatStart, + [DEBUG_UTIL_MENU_ITEM_HATCH_AN_EGG] = DebugAction_Util_HatchAnEgg, }; static void (*const sDebugMenu_Actions_Scripts[])(u8) = { @@ -1132,6 +1140,8 @@ static void Debug_RefreshListMenu(u8 taskId) totalItems = 7; } + // Failsafe to prevent memory corruption + totalItems = min(totalItems, DEBUG_MAX_MENU_ITEMS); // Copy item names for all entries but the last (which is Cancel) for(i = 0; i < totalItems; i++) { @@ -1976,6 +1986,10 @@ static void DebugAction_Util_CheatStart(u8 taskId) { Debug_DestroyMenu_Full_Script(taskId, Debug_CheatStart); } +static void DebugAction_Util_HatchAnEgg(u8 taskId) +{ + Debug_DestroyMenu_Full_Script(taskId, Debug_HatchAnEgg); +} // ******************************* // Actions Scripts diff --git a/src/pokemon.c b/src/pokemon.c index 881eeab8bc..4347d7a0ee 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -8549,7 +8549,7 @@ bool32 TryFormChange(u32 monId, u32 side, u16 method) targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0); if (targetSpecies == SPECIES_NONE && gBattleStruct != NULL) - targetSpecies = gBattleStruct->changedSpecies[monId]; + targetSpecies = gBattleStruct->changedSpecies[side][monId]; if (targetSpecies != SPECIES_NONE) { diff --git a/src/random.c b/src/random.c index dded1ec6f9..6a462004b4 100644 --- a/src/random.c +++ b/src/random.c @@ -80,6 +80,9 @@ void ShuffleN(void *data, size_t n, size_t size) __attribute__((weak, alias("RandomUniformDefault"))) u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi); +__attribute__((weak, alias("RandomUniformExceptDefault"))) +u32 RandomUniformExcept(enum RandomTag, u32 lo, u32 hi, bool32 (*reject)(u32)); + __attribute__((weak, alias("RandomWeightedArrayDefault"))) u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights); @@ -91,6 +94,16 @@ u32 RandomUniformDefault(enum RandomTag tag, u32 lo, u32 hi) return lo + (((hi - lo + 1) * Random()) >> 16); } +u32 RandomUniformExceptDefault(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32)) +{ + while (TRUE) + { + u32 n = RandomUniformDefault(tag, lo, hi); + if (!reject(n)) + return n; + } +} + u32 RandomWeightedArrayDefault(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) { s32 i, targetSum; diff --git a/test/ability_beads_of_ruin.c b/test/ability_beads_of_ruin.c new file mode 100644 index 0000000000..28b39a430c --- /dev/null +++ b/test/ability_beads_of_ruin.c @@ -0,0 +1,53 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_WATER_GUN].split == SPLIT_SPECIAL); +} + +SINGLE_BATTLE_TEST("Beads of Ruin reduces Sp. Def", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { ability = ABILITY_BEADS_OF_RUIN; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_WATER_GUN); } + } SCENE { + if (ability == ABILITY_BEADS_OF_RUIN) { + ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN); + MESSAGE("Wobbuffet's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + } + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.25), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Beads of Ruin does not reduce Sp. Def if opposing mon has the same ability", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { ability = ABILITY_BEADS_OF_RUIN; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_BEADS_OF_RUIN); } + } WHEN { + TURN { MOVE(player, MOVE_WATER_GUN); } + } SCENE { + if (ability == ABILITY_BEADS_OF_RUIN) { + ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN); + MESSAGE("Wobbuffet's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + } + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} diff --git a/test/ability_protosynthesis.c b/test/ability_protosynthesis.c new file mode 100644 index 0000000000..9f794e00a7 --- /dev/null +++ b/test/ability_protosynthesis.c @@ -0,0 +1,87 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); + ASSUME(gBattleMoves[MOVE_ROUND].split == SPLIT_SPECIAL); +} + +SINGLE_BATTLE_TEST("Protosynthesis boosts the highest stat") +{ + GIVEN { + PLAYER(SPECIES_ABRA) { Ability(ABILITY_PROTOSYNTHESIS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player); + ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); + MESSAGE("The harsh sunlight activated Abra's Protosynthesis!"); + MESSAGE("Abra's Sp. Atk was heightened!"); + } +} + +SINGLE_BATTLE_TEST("Protosynthesis boosts either Attack or Special Attack, not both") +{ + u16 species; + u32 move; + u16 damage[2]; + + PARAMETRIZE { species = SPECIES_BELLSPROUT; move = MOVE_TACKLE; } + PARAMETRIZE { species = SPECIES_BELLSPROUT; move = MOVE_ROUND; } + + PARAMETRIZE { species = SPECIES_ABRA; move = MOVE_TACKLE; } + PARAMETRIZE { species = SPECIES_ABRA; move = MOVE_ROUND; } + + GIVEN { + PLAYER(species) { Ability(ABILITY_PROTOSYNTHESIS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent); + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent, captureDamage: &damage[1]); + } THEN { + if ((move == MOVE_TACKLE && species == SPECIES_BELLSPROUT) || (move == MOVE_ROUND && species == SPECIES_ABRA)) + EXPECT_MUL_EQ(damage[0], Q_4_12(1.3), damage[1]); + else + EXPECT_EQ(damage[0], damage[1]); + } +} + +SINGLE_BATTLE_TEST("Protosynthesis either boosts Defense or Special Defense, not both") +{ + u16 species; + u32 move; + u16 damage[2]; + + PARAMETRIZE { species = SPECIES_ONIX; move = MOVE_TACKLE; } + PARAMETRIZE { species = SPECIES_ONIX; move = MOVE_ROUND; } + + PARAMETRIZE { species = SPECIES_BLASTOISE; move = MOVE_TACKLE; } + PARAMETRIZE { species = SPECIES_BLASTOISE; move = MOVE_ROUND; } + + GIVEN { + PLAYER(species) { Ability(ABILITY_PROTOSYNTHESIS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + TURN { MOVE(player, MOVE_SUNNY_DAY); MOVE(opponent, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + HP_BAR(player, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player); + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + HP_BAR(player, captureDamage: &damage[1]); + } THEN { + if ((move == MOVE_TACKLE && species == SPECIES_ONIX) || (move == MOVE_ROUND && species == SPECIES_BLASTOISE)) + EXPECT_MUL_EQ(damage[0], Q_4_12(0.7), damage[1]); + else + EXPECT_EQ(damage[0], damage[1]); + } +} diff --git a/test/ability_quark_drive.c b/test/ability_quark_drive.c new file mode 100644 index 0000000000..b004c760c4 --- /dev/null +++ b/test/ability_quark_drive.c @@ -0,0 +1,87 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); + ASSUME(gBattleMoves[MOVE_ROUND].split == SPLIT_SPECIAL); +} + +SINGLE_BATTLE_TEST("Quark Drive boosts the highest stat") +{ + GIVEN { + PLAYER(SPECIES_ABRA) { Ability(ABILITY_QUARK_DRIVE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player); + ABILITY_POPUP(player, ABILITY_QUARK_DRIVE); + MESSAGE("The Electric Terrain activated Abra's Quark Drive!"); + MESSAGE("Abra's Sp. Atk was heightened!"); + } +} + +SINGLE_BATTLE_TEST("Quark Drive boosts either Attack or Special Attack, not both") +{ + u16 species; + u32 move; + u16 damage[2]; + + PARAMETRIZE { species = SPECIES_BELLSPROUT; move = MOVE_TACKLE; } + PARAMETRIZE { species = SPECIES_BELLSPROUT; move = MOVE_ROUND; } + + PARAMETRIZE { species = SPECIES_ABRA; move = MOVE_TACKLE; } + PARAMETRIZE { species = SPECIES_ABRA; move = MOVE_ROUND; } + + GIVEN { + PLAYER(species) { Ability(ABILITY_QUARK_DRIVE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + TURN { MOVE(opponent, MOVE_ELECTRIC_TERRAIN); MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, opponent); + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent, captureDamage: &damage[1]); + } THEN { + if ((move == MOVE_TACKLE && species == SPECIES_BELLSPROUT) || (move == MOVE_ROUND && species == SPECIES_ABRA)) + EXPECT_MUL_EQ(damage[0], Q_4_12(1.3), damage[1]); + else + EXPECT_EQ(damage[0], damage[1]); + } +} + +SINGLE_BATTLE_TEST("Quark Drive either boosts Defense or Special Defense, not both") +{ + u16 species; + u32 move; + u16 damage[2]; + + PARAMETRIZE { species = SPECIES_ONIX; move = MOVE_TACKLE; } + PARAMETRIZE { species = SPECIES_ONIX; move = MOVE_ROUND; } + + PARAMETRIZE { species = SPECIES_BLASTOISE; move = MOVE_TACKLE; } + PARAMETRIZE { species = SPECIES_BLASTOISE; move = MOVE_ROUND; } + + GIVEN { + PLAYER(species) { Ability(ABILITY_QUARK_DRIVE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); MOVE(opponent, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + HP_BAR(player, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player); + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + HP_BAR(player, captureDamage: &damage[1]); + } THEN { + if ((move == MOVE_TACKLE && species == SPECIES_ONIX) || (move == MOVE_ROUND && species == SPECIES_BLASTOISE)) + EXPECT_MUL_EQ(damage[0], Q_4_12(0.7), damage[1]); + else + EXPECT_EQ(damage[0], damage[1]); + } +} diff --git a/test/ability_sword_of_ruin.c b/test/ability_sword_of_ruin.c new file mode 100644 index 0000000000..6ec4f8fe85 --- /dev/null +++ b/test/ability_sword_of_ruin.c @@ -0,0 +1,53 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); +} + +SINGLE_BATTLE_TEST("Sword of Ruin reduces Defense", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { ability = ABILITY_SWORD_OF_RUIN; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + if (ability == ABILITY_SWORD_OF_RUIN) { + ABILITY_POPUP(player, ABILITY_SWORD_OF_RUIN); + MESSAGE("Wobbuffet's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + } + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.25), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Sword of Ruin does not reduce Defense if opposing mon has the same ability", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { ability = ABILITY_SWORD_OF_RUIN; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_SWORD_OF_RUIN); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + if (ability == ABILITY_SWORD_OF_RUIN) { + ABILITY_POPUP(player, ABILITY_SWORD_OF_RUIN); + MESSAGE("Wobbuffet's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + } + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} diff --git a/test/ability_tablets_of_ruin.c b/test/ability_tablets_of_ruin.c new file mode 100644 index 0000000000..38dcfc8560 --- /dev/null +++ b/test/ability_tablets_of_ruin.c @@ -0,0 +1,53 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); +} + +SINGLE_BATTLE_TEST("Tablets of Ruin reduces Attack", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { ability = ABILITY_TABLETS_OF_RUIN; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (ability == ABILITY_TABLETS_OF_RUIN) { + ABILITY_POPUP(player, ABILITY_TABLETS_OF_RUIN); + MESSAGE("Wobbuffet's Tablets of Ruin weakened the Attack of all surrounding Pokémon!"); + } + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.75), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Tablets of Ruin does not reduce Attack if an opposing mon has the same ability", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { ability = ABILITY_TABLETS_OF_RUIN; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TABLETS_OF_RUIN); } + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (ability == ABILITY_TABLETS_OF_RUIN) { + ABILITY_POPUP(player, ABILITY_TABLETS_OF_RUIN); + MESSAGE("Wobbuffet's Tablets of Ruin weakened the Attack of all surrounding Pokémon!"); + } + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} diff --git a/test/ability_vessel_of_ruin.c b/test/ability_vessel_of_ruin.c new file mode 100644 index 0000000000..6c7b2664f2 --- /dev/null +++ b/test/ability_vessel_of_ruin.c @@ -0,0 +1,53 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_WATER_GUN].split == SPLIT_SPECIAL); +} + +SINGLE_BATTLE_TEST("Vessel of Ruin reduces Sp. Atk", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { ability = ABILITY_VESSEL_OF_RUIN; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_WATER_GUN); } + } SCENE { + if (ability == ABILITY_VESSEL_OF_RUIN) { + ABILITY_POPUP(player, ABILITY_VESSEL_OF_RUIN); + MESSAGE("Wobbuffet's Vessel of Ruin weakened the Sp. Atk of all surrounding Pokémon!"); + } + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.75), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Vessel of Ruin does not reduce Sp. Atk if opposing mon has the same ability", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { ability = ABILITY_VESSEL_OF_RUIN; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_VESSEL_OF_RUIN); } + } WHEN { + TURN { MOVE(opponent, MOVE_WATER_GUN); } + } SCENE { + if (ability == ABILITY_VESSEL_OF_RUIN) { + ABILITY_POPUP(player, ABILITY_VESSEL_OF_RUIN); + MESSAGE("Wobbuffet's Vessel of Ruin weakened the Sp. Atk of all surrounding Pokémon!"); + } + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} diff --git a/test/hold_effect_gems.c b/test/hold_effect_gems.c new file mode 100644 index 0000000000..9a90b81f9d --- /dev/null +++ b/test/hold_effect_gems.c @@ -0,0 +1,89 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gItems[ITEM_NORMAL_GEM].holdEffect == HOLD_EFFECT_GEMS); +} + +SINGLE_BATTLE_TEST("Gem is consumed when it corresponds to the type of a move") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_EMBER); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Fire Gem strengthened Wobbuffet's power!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Normal Gem strengthened Wobbuffet's power!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + } +} + +SINGLE_BATTLE_TEST("Gem boost is only applied once") +{ + s16 boostedHit; + s16 normalHit; + + GIVEN { + ASSUME(I_GEM_BOOST_POWER >= GEN_5); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Normal Gem strengthened Wobbuffet's power!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + HP_BAR(opponent, captureDamage: &boostedHit); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + HP_BAR(opponent, captureDamage: &normalHit); + } THEN { + EXPECT_MUL_EQ(normalHit, Q_4_12(1.3), boostedHit); + } +} + +SINGLE_BATTLE_TEST("Gem modifier is used for all hits of Multi Hit Moves") +{ + s16 firstHit; + s16 secondHit; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { + MOVE(player, MOVE_DOUBLE_HIT); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_HIT, player); + HP_BAR(opponent, captureDamage: &firstHit); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_HIT, player); + HP_BAR(opponent, captureDamage: &secondHit); + } THEN { + EXPECT_EQ(firstHit, secondHit); + } +} + +SINGLE_BATTLE_TEST("Gem is consumed if the move type is changed") +{ + GIVEN { + PLAYER(SPECIES_DELCATTY) { Ability(ABILITY_NORMALIZE); Item(ITEM_NORMAL_GEM); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { + MOVE(player, MOVE_FEINT_ATTACK); + } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Normal Gem strengthened Delcatty's power!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FEINT_ATTACK, player); + } +} diff --git a/test/hold_effect_utility_umbrella.c b/test/hold_effect_utility_umbrella.c new file mode 100644 index 0000000000..6716ee72fd --- /dev/null +++ b/test/hold_effect_utility_umbrella.c @@ -0,0 +1,54 @@ +#include "global.h" +#include "test_battle.h" + +// Please add Utility Umbrella interactions with move, item and ability effects on their respective files. +ASSUMPTIONS +{ + ASSUME(gItems[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA); + ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE); + ASSUME(gBattleMoves[MOVE_WATER_GUN].type == TYPE_WATER); +} + +SINGLE_BATTLE_TEST("Utility Umbrella blocks Sun damage modifiers", s16 damage) +{ + u16 setupMove, attackingMove, heldItem; + PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; attackingMove = MOVE_EMBER; heldItem = ITEM_UTILITY_UMBRELLA; } + PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; attackingMove = MOVE_EMBER; heldItem = ITEM_NONE; } + PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; attackingMove = MOVE_WATER_GUN; heldItem = ITEM_UTILITY_UMBRELLA; } + PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; attackingMove = MOVE_WATER_GUN; heldItem = ITEM_NONE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(heldItem); }; + } WHEN { + TURN { MOVE(opponent, setupMove); } + TURN { MOVE(player, attackingMove); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, attackingMove, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + EXPECT_MUL_EQ(results[2].damage, Q_4_12(0.5), results[3].damage); + } +} + +SINGLE_BATTLE_TEST("Utility Umbrella blocks Rain damage modifiers", s16 damage) +{ + u16 setupMove, attackingMove, heldItem; + PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; attackingMove = MOVE_EMBER; heldItem = ITEM_UTILITY_UMBRELLA; } + PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; attackingMove = MOVE_EMBER; heldItem = ITEM_NONE; } + PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; attackingMove = MOVE_WATER_GUN; heldItem = ITEM_UTILITY_UMBRELLA; } + PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; attackingMove = MOVE_WATER_GUN; heldItem = ITEM_NONE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(heldItem); }; + } WHEN { + TURN { MOVE(opponent, setupMove); } + TURN { MOVE(player, attackingMove); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, attackingMove, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.5), results[3].damage); + } +} diff --git a/test/move_effect_collision_course.c b/test/move_effect_collision_course.c new file mode 100644 index 0000000000..bcf3cdd724 --- /dev/null +++ b/test/move_effect_collision_course.c @@ -0,0 +1,47 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_COLLISION_COURSE].effect == EFFECT_COLLISION_COURSE); +} + +SINGLE_BATTLE_TEST("Collision Course damage is increased by 33 Percent if super effective", s16 damage) +{ + u32 move; + + PARAMETRIZE { move = MOVE_HAMMER_ARM; } + PARAMETRIZE { move = MOVE_COLLISION_COURSE; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KANGASKHAN); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.3333), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Collision Course does normal damage if not super effective", s16 damage) +{ + u32 move; + + PARAMETRIZE { move = MOVE_HAMMER_ARM; } + PARAMETRIZE { move = MOVE_COLLISION_COURSE; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} diff --git a/test/move_effect_hydro_steam.c b/test/move_effect_hydro_steam.c new file mode 100644 index 0000000000..4874491594 --- /dev/null +++ b/test/move_effect_hydro_steam.c @@ -0,0 +1,50 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_HYDRO_STEAM].effect == EFFECT_HYDRO_STEAM); +} + +SINGLE_BATTLE_TEST("Hydro Steam deals 1.5x damage under both Sunlight and Rain", s16 damage) +{ + u16 setupMove; + PARAMETRIZE { setupMove = MOVE_CELEBRATE; } + PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; } + PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, setupMove); } + TURN { MOVE(player, MOVE_HYDRO_STEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HYDRO_STEAM, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[2].damage); + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Hydro Steam is affected by Utility Umbrella", s16 damage) +{ + u32 itemPlayer; + u32 itemOpponent; + PARAMETRIZE { itemPlayer = ITEM_UTILITY_UMBRELLA; itemOpponent = ITEM_NONE; } + PARAMETRIZE { itemPlayer = ITEM_NONE; itemOpponent = ITEM_UTILITY_UMBRELLA; } + PARAMETRIZE { itemPlayer = ITEM_UTILITY_UMBRELLA; itemOpponent = ITEM_UTILITY_UMBRELLA; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(itemPlayer); }; + OPPONENT(SPECIES_WOBBUFFET) {Item(itemOpponent); }; + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); } + TURN { MOVE(player, MOVE_HYDRO_STEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HYDRO_STEAM, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[2].damage, Q_4_12(1.5), results[1].damage); + EXPECT_MUL_EQ(results[2].damage, Q_4_12(0.5), results[0].damage); + } +} diff --git a/test/move_effect_make_it_rain.c b/test/move_effect_make_it_rain.c new file mode 100644 index 0000000000..ae8149b198 --- /dev/null +++ b/test/move_effect_make_it_rain.c @@ -0,0 +1,34 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_MAKE_IT_RAIN].effect == EFFECT_MAKE_IT_RAIN); +} + +SINGLE_BATTLE_TEST("Make It Rain lowers special attack by one stage") +{ + s16 damage[2]; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_MAKE_IT_RAIN); } + TURN { MOVE(player, MOVE_MAKE_IT_RAIN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAKE_IT_RAIN, player); + HP_BAR(opponent, captureDamage: &damage[0]); + MESSAGE("Coins scattered everywhere!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Sp. Atk fell!"); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAKE_IT_RAIN, player); + HP_BAR(opponent, captureDamage: &damage[1]); + MESSAGE("Coins scattered everywhere!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Sp. Atk fell!"); + } THEN { + EXPECT_MUL_EQ(damage[0], Q_4_12(0.66), damage[1]); + } +} diff --git a/test/move_effect_metronome.c b/test/move_effect_metronome.c index 588b391ecf..5b2fb0babe 100644 --- a/test/move_effect_metronome.c +++ b/test/move_effect_metronome.c @@ -6,19 +6,13 @@ ASSUMPTIONS ASSUME(gBattleMoves[MOVE_METRONOME].effect == EFFECT_METRONOME); } -// To do: Turn the seeds to work with WITH_RNG for Metronome. -#define RNG_METRONOME_SCRATCH 0x118 -#define RNG_METRONOME_PSN_POWDER 0x119 -#define RNG_METRONOME_ROCK_BLAST 0x1F5 - SINGLE_BATTLE_TEST("Metronome picks a random move") { GIVEN { - RNGSeed(RNG_METRONOME_SCRATCH); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_METRONOME); } + TURN { MOVE(player, MOVE_METRONOME, WITH_RNG(RNG_METRONOME, MOVE_SCRATCH)); } } SCENE { MESSAGE("Wobbuffet used Metronome!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_METRONOME, player); @@ -34,11 +28,10 @@ SINGLE_BATTLE_TEST("Metronome's called powder move fails against Grass Types") ASSUME(gBattleMoves[MOVE_POISON_POWDER].powderMove); ASSUME(gSpeciesInfo[SPECIES_TANGELA].types[0] == TYPE_GRASS); ASSUME(gBattleMoves[MOVE_POISON_POWDER].effect == EFFECT_POISON); - RNGSeed(RNG_METRONOME_PSN_POWDER); - PLAYER(SPECIES_WOBBUFFET) {Speed(5);} - OPPONENT(SPECIES_TANGELA) {Speed(2);} + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_TANGELA); } WHEN { - TURN { MOVE(player, MOVE_METRONOME); } + TURN { MOVE(player, MOVE_METRONOME, WITH_RNG(RNG_METRONOME, MOVE_POISON_POWDER)); } } SCENE { MESSAGE("Wobbuffet used Metronome!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_METRONOME, player); @@ -53,17 +46,16 @@ SINGLE_BATTLE_TEST("Metronome's called multi-hit move hits multiple times") { GIVEN { ASSUME(gBattleMoves[MOVE_ROCK_BLAST].effect == EFFECT_MULTI_HIT); - RNGSeed(RNG_METRONOME_ROCK_BLAST); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_METRONOME); } + TURN { MOVE(player, MOVE_METRONOME, WITH_RNG(RNG_METRONOME, MOVE_ROCK_BLAST)); } } SCENE { MESSAGE("Wobbuffet used Metronome!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_METRONOME, player); MESSAGE("Wobbuffet used Rock Blast!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_BLAST, player); HP_BAR(opponent); - MESSAGE("Hit 4 time(s)!"); + MESSAGE("Hit 5 time(s)!"); } } diff --git a/test/move_effect_mirror_move.c b/test/move_effect_mirror_move.c index 568be15a59..ec77721241 100644 --- a/test/move_effect_mirror_move.c +++ b/test/move_effect_mirror_move.c @@ -9,8 +9,8 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Mirror Move copies the last used move by the target") { GIVEN { - PLAYER(SPECIES_WOBBUFFET) {Speed(2);} - OPPONENT(SPECIES_WOBBUFFET) {Speed(5);} + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_MIRROR_MOVE); } } SCENE { @@ -26,10 +26,10 @@ SINGLE_BATTLE_TEST("Mirror Move copies the last used move by the target") SINGLE_BATTLE_TEST("Mirror Move fails if no move was used before") { GIVEN { - PLAYER(SPECIES_WOBBUFFET) {Speed(5);} - OPPONENT(SPECIES_WOBBUFFET) {Speed(2);} + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_MIRROR_MOVE); } + TURN { MOVE(player, MOVE_MIRROR_MOVE); MOVE(opponent, MOVE_TACKLE); } } SCENE { MESSAGE("Wobbuffet used Mirror Move!"); MESSAGE("The Mirror Move failed!"); @@ -44,8 +44,8 @@ SINGLE_BATTLE_TEST("Mirror Move's called powder move fails against Grass Types") ASSUME(gBattleMoves[MOVE_STUN_SPORE].powderMove); ASSUME(gSpeciesInfo[SPECIES_ODDISH].types[0] == TYPE_GRASS); ASSUME(gBattleMoves[MOVE_STUN_SPORE].effect == EFFECT_PARALYZE); - PLAYER(SPECIES_ODDISH) {Speed(5);} - OPPONENT(SPECIES_WOBBUFFET) {Speed(2);} + PLAYER(SPECIES_ODDISH); + OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_STUN_SPORE); MOVE(opponent, MOVE_MIRROR_MOVE); } } SCENE { @@ -59,19 +59,18 @@ SINGLE_BATTLE_TEST("Mirror Move's called powder move fails against Grass Types") } } -// It hits first 2 times, then 5 times with the default rng seed. SINGLE_BATTLE_TEST("Mirror Move's called multi-hit move hits multiple times") { GIVEN { ASSUME(gBattleMoves[MOVE_BULLET_SEED].effect == EFFECT_MULTI_HIT); - PLAYER(SPECIES_WOBBUFFET) {Speed(5);} - OPPONENT(SPECIES_WOBBUFFET) {Speed(2);} + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_BULLET_SEED); MOVE(opponent, MOVE_MIRROR_MOVE); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player); HP_BAR(opponent); - MESSAGE("Hit 2 time(s)!"); + MESSAGE("Hit 5 time(s)!"); MESSAGE("Foe Wobbuffet used Mirror Move!"); MESSAGE("Foe Wobbuffet used Bullet Seed!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, opponent); diff --git a/test/move_effect_spin_out.c b/test/move_effect_spin_out.c new file mode 100644 index 0000000000..060f3545ec --- /dev/null +++ b/test/move_effect_spin_out.c @@ -0,0 +1,21 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_SPIN_OUT].effect == EFFECT_SPIN_OUT); +} + +SINGLE_BATTLE_TEST("Spin Out lowers speed by 2 stages") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SPIN_OUT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIN_OUT, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Speed harshly fell!"); + } +} diff --git a/test/primal_reversion.c b/test/primal_reversion.c new file mode 100644 index 0000000000..f888d17f7e --- /dev/null +++ b/test/primal_reversion.c @@ -0,0 +1,216 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Primal reversion happens for Groudon only when holding Red Orb") +{ + u16 heldItem; + PARAMETRIZE { heldItem = ITEM_NONE;} + PARAMETRIZE { heldItem = ITEM_RED_ORB;} + PARAMETRIZE { heldItem = ITEM_BLUE_ORB;} + GIVEN { + PLAYER(SPECIES_GROUDON) { Item(heldItem); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + } SCENE { + if (heldItem == ITEM_RED_ORB) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + } + else { + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + } + } + } THEN { + if (heldItem == ITEM_RED_ORB) { + EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL); + } + else { + EXPECT_EQ(player->species, SPECIES_GROUDON); + } + } +} + +SINGLE_BATTLE_TEST("Primal reversion happens for Kyogre only when holding Blue Orb") +{ + u16 heldItem; + PARAMETRIZE { heldItem = ITEM_NONE;} + PARAMETRIZE { heldItem = ITEM_RED_ORB;} + PARAMETRIZE { heldItem = ITEM_BLUE_ORB;} + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KYOGRE) { Item(heldItem); } + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + if (heldItem == ITEM_BLUE_ORB) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponent); + MESSAGE("Foe Kyogre's Primal Reversion! It reverted to its primal form!"); + } + else { + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponent); + MESSAGE("Foe Kyogre's Primal Reversion! It reverted to its primal form!"); + } + } + } THEN { + if (heldItem == ITEM_BLUE_ORB) { + EXPECT_EQ(opponent->species, SPECIES_KYOGRE_PRIMAL); + } + else { + EXPECT_EQ(opponent->species, SPECIES_KYOGRE); + } + } +} + +DOUBLE_BATTLE_TEST("Primal reversion's order is determined by Speed - opponent faster") +{ + GIVEN { + PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); Speed(5); }; + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(15); }; + OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(10); } + OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); Speed(20); } + } WHEN { + TURN { MOVE(opponentLeft, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponentRight); + MESSAGE("Foe Kyogre's Primal Reversion! It reverted to its primal form!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, playerRight); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponentLeft); + MESSAGE("Foe Groudon's Primal Reversion! It reverted to its primal form!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, playerLeft); + MESSAGE("Kyogre's Primal Reversion! It reverted to its primal form!"); + } THEN { + EXPECT_EQ(playerLeft->species, SPECIES_KYOGRE_PRIMAL); + EXPECT_EQ(opponentLeft->species, SPECIES_GROUDON_PRIMAL); + EXPECT_EQ(opponentRight->species, SPECIES_KYOGRE_PRIMAL); + EXPECT_EQ(playerRight->species, SPECIES_GROUDON_PRIMAL); + } +} + +DOUBLE_BATTLE_TEST("Primal reversion's order is determined by Speed - player faster") +{ + GIVEN { + PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); Speed(20); }; + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(30); }; + OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(10); } + OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); Speed(2); } + } WHEN { + TURN { MOVE(opponentLeft, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, playerRight); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, playerLeft); + MESSAGE("Kyogre's Primal Reversion! It reverted to its primal form!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponentLeft); + MESSAGE("Foe Groudon's Primal Reversion! It reverted to its primal form!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, opponentRight); + MESSAGE("Foe Kyogre's Primal Reversion! It reverted to its primal form!"); + } THEN { + EXPECT_EQ(playerLeft->species, SPECIES_KYOGRE_PRIMAL); + EXPECT_EQ(opponentLeft->species, SPECIES_GROUDON_PRIMAL); + EXPECT_EQ(opponentRight->species, SPECIES_KYOGRE_PRIMAL); + EXPECT_EQ(playerRight->species, SPECIES_GROUDON_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Primal reversion happens after a mon is sent out after a mon is fainted") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_TACKLE].power != 0); + PLAYER(SPECIES_WOBBUFFET) {HP(1); } + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + MESSAGE("Wobbuffet fainted!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Primal reversion happens after a mon is switched in") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { SWITCH(player, 1); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Eject Button") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_TACKLE].power != 0); + ASSUME(gItems[ITEM_EJECT_BUTTON].holdEffect == HOLD_EFFECT_EJECT_BUTTON); + PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_EJECT_BUTTON); } + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + MESSAGE("Wobbuffet is switched out with the Eject Button!"); + MESSAGE("Go! Groudon!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Red Card") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_TACKLE].power != 0); + ASSUME(gItems[ITEM_RED_CARD].holdEffect == HOLD_EFFECT_RED_CARD); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + OPPONENT(SPECIES_WOBBUFFET) {Item(ITEM_RED_CARD); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + MESSAGE("Foe Wobbuffet held up its Red Card against Wobbuffet!"); + MESSAGE("Groudon was dragged out!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Primal reversion happens after the entry hazards damage") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_SPIKES].effect == EFFECT_SPIKES); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SPIKES); } + TURN { MOVE(opponent, MOVE_SPIKES); SWITCH(player, 1);} + } SCENE { + MESSAGE("Go! Groudon!"); + HP_BAR(player); + MESSAGE("Groudon is hurt by spikes!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + MESSAGE("Groudon's Primal Reversion! It reverted to its primal form!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_GROUDON_PRIMAL); + } +} diff --git a/test/random.c b/test/random.c index ef364de276..3bc0f75c6d 100644 --- a/test/random.c +++ b/test/random.c @@ -57,6 +57,25 @@ TEST("RandomUniform generates lo..hi") } } +static bool32 InvalidEven(u32 n) +{ + return n % 2 == 0; +} + +TEST("RandomUniformExcept generates lo..hi") +{ + u32 lo, hi, i; + PARAMETRIZE { lo = 0; hi = 1; } + PARAMETRIZE { lo = 0; hi = 2; } + PARAMETRIZE { lo = 0; hi = 3; } + PARAMETRIZE { lo = 2; hi = 4; } + for (i = 0; i < 1024; i++) + { + u32 r = RandomUniformExceptDefault(RNG_NONE, lo, hi, InvalidEven); + EXPECT(lo <= r && r <= hi && r % 2 != 0); + } +} + TEST("RandomWeighted generates 0..n-1") { u32 n, sum, i; @@ -106,6 +125,29 @@ TEST("RandomUniform generates uniform distribution") EXPECT_LT(error, UQ_4_12(0.025)); } +TEST("RandomUniformExcept generates uniform distribution") +{ + u32 i, error; + u16 distribution[4]; + + memset(distribution, 0, sizeof(distribution)); + for (i = 0; i < 4096; i++) + { + u32 r = RandomUniformExceptDefault(RNG_NONE, 0, ARRAY_COUNT(distribution) - 1, InvalidEven); + EXPECT(0 <= r && r < ARRAY_COUNT(distribution)); + distribution[r]++; + } + + error = 0; + for (i = 0; i < ARRAY_COUNT(distribution); i++) + { + if (i % 2 != 0) + error += abs(UQ_4_12(0.5) - distribution[i]); + } + + EXPECT_LT(error, UQ_4_12(0.05)); +} + TEST("RandomWeighted generates distribution in proportion to the weights") { u32 i, sum, error; diff --git a/test/test_battle.h b/test/test_battle.h index 49f112fa5d..74a3bc2e82 100644 --- a/test/test_battle.h +++ b/test/test_battle.h @@ -603,8 +603,9 @@ struct BattleTestRunnerState u8 parameters; u8 runParameter; u16 rngTag; - u8 trials; - u8 runTrial; + u16 rngTrialOffset; + u16 trials; + u16 runTrial; u16 expectedRatio; u16 observedRatio; u16 trialRatio; diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 592d0db980..4de144c38a 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -307,17 +307,13 @@ static void BattleTest_Run(void *data) u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi) { const struct BattlerTurn *turn = NULL; - u32 default_ = hi; if (gCurrentTurnActionNumber < gBattlersCount) { u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; - } - - if (turn && turn->rng.tag == tag) - { - default_ = turn->rng.value; + if (turn && turn->rng.tag == tag) + return turn->rng.value; } if (tag == STATE->rngTag) @@ -332,53 +328,76 @@ u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi) { Test_ExitWithResult(TEST_RESULT_ERROR, "RandomUniform called with inconsistent trials %d and %d", STATE->trials, n); } - STATE->trialRatio = Q_4_12(1) / n; + STATE->trialRatio = Q_4_12(1) / STATE->trials; return STATE->runTrial + lo; } + return hi; +} + +u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32)) +{ + const struct BattlerTurn *turn = NULL; + u32 default_; + + if (gCurrentTurnActionNumber < gBattlersCount) + { + u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; + if (turn && turn->rng.tag == tag) + { + if (reject(turn->rng.value)) + Test_ExitWithResult(TEST_RESULT_INVALID, "WITH_RNG specified a rejected value (%d)", turn->rng.value); + return turn->rng.value; + } + } + + if (tag == STATE->rngTag) + { + if (STATE->trials == 1) + { + u32 n = 0, i; + for (i = lo; i < hi; i++) + if (!reject(i)) + n++; + STATE->trials = n; + PrintTestName(); + } + STATE->trialRatio = Q_4_12(1) / STATE->trials; + + while (reject(STATE->runTrial + lo + STATE->rngTrialOffset)) + { + if (STATE->runTrial + lo + STATE->rngTrialOffset > hi) + Test_ExitWithResult(TEST_RESULT_INVALID, "RandomUniformExcept called with inconsistent reject"); + STATE->rngTrialOffset++; + } + + return STATE->runTrial + lo + STATE->rngTrialOffset; + } + + default_ = hi; + while (reject(default_)) + { + if (default_ == lo) + Test_ExitWithResult(TEST_RESULT_INVALID, "RandomUniformExcept rejected all values"); + default_--; + } return default_; } u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) { const struct BattlerTurn *turn = NULL; - u32 default_ = n-1; + + if (sum == 0) + Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeightedArray called with zero sum"); if (gCurrentTurnActionNumber < gBattlersCount) { u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; - } - - if (turn && turn->rng.tag == tag) - { - default_ = turn->rng.value; - } - else - { - switch (tag) - { - case RNG_ACCURACY: - ASSUME(n == 2); - if (turn && turn->hit) - return turn->hit - 1; - default_ = TRUE; - break; - - case RNG_CRITICAL_HIT: - ASSUME(n == 2); - if (turn && turn->criticalHit) - return turn->criticalHit - 1; - default_ = FALSE; - break; - - case RNG_SECONDARY_EFFECT: - ASSUME(n == 2); - if (turn && turn->secondaryEffect) - return turn->secondaryEffect - 1; - default_ = TRUE; - break; - } + if (turn && turn->rng.tag == tag) + return turn->rng.value; } if (tag == STATE->rngTag) @@ -397,7 +416,38 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) return STATE->runTrial; } - return default_; + switch (tag) + { + case RNG_ACCURACY: + ASSUME(n == 2); + if (turn && turn->hit) + return turn->hit - 1; + else + return TRUE; + + case RNG_CRITICAL_HIT: + ASSUME(n == 2); + if (turn && turn->criticalHit) + return turn->criticalHit - 1; + else + return FALSE; + + case RNG_SECONDARY_EFFECT: + ASSUME(n == 2); + if (turn && turn->secondaryEffect) + return turn->secondaryEffect - 1; + else + return TRUE; + + default: + while (weights[n-1] == 0) + { + if (n == 1) + Test_ExitWithResult(TEST_RESULT_ERROR, "RandomWeightedArray called with all zero weights"); + n--; + } + return n-1; + } } const void *RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count) @@ -409,22 +459,17 @@ const void *RandomElementArray(enum RandomTag tag, const void *array, size_t siz { u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; - } - - if (turn && turn->rng.tag == tag) - { - u32 element = 0; - for (index = 0; index < count; index++) - { - memcpy(&element, (const u8 *)array + size * index, size); - if (element == turn->rng.value) - break; - } - if (index == count) + if (turn && turn->rng.tag == tag) { + u32 element = 0; + for (index = 0; index < count; index++) + { + memcpy(&element, (const u8 *)array + size * index, size); + if (element == turn->rng.value) + return (const u8 *)array + size * index; + } // TODO: Incorporate the line number. - const char *filename = gTestRunnerState.test->filename; - Test_ExitWithResult(TEST_RESULT_ERROR, "%s: RandomElement illegal value requested: %d", filename, turn->rng.value); + Test_ExitWithResult(TEST_RESULT_ERROR, "%s: RandomElement illegal value requested: %d", gTestRunnerState.test->filename, turn->rng.value); } } @@ -440,10 +485,8 @@ const void *RandomElementArray(enum RandomTag tag, const void *array, size_t siz Test_ExitWithResult(TEST_RESULT_ERROR, "RandomElement called with inconsistent trials %d and %d", STATE->trials, count); } STATE->trialRatio = Q_4_12(1) / count; - index = STATE->runTrial; + return (const u8 *)array + size * STATE->runTrial; } - - return (const u8 *)array + size * index; } static s32 TryAbilityPopUp(s32 i, s32 n, u32 battlerId, u32 ability) @@ -962,6 +1005,7 @@ void Randomly(u32 sourceLine, u32 passes, u32 trials, struct RandomlyContext ctx INVALID_IF(test->resultsSize > 0, "PASSES_RANDOMLY is incompatible with results"); INVALID_IF(passes > trials, "%d passes specified, but only %d trials", passes, trials); STATE->rngTag = ctx.tag; + STATE->rngTrialOffset = 0; STATE->runTrial = 0; STATE->expectedRatio = Q_4_12(passes) / trials; STATE->observedRatio = 0; diff --git a/test/weather_rain.c b/test/weather_rain.c new file mode 100644 index 0000000000..b996814951 --- /dev/null +++ b/test/weather_rain.c @@ -0,0 +1,47 @@ +#include "global.h" +#include "test_battle.h" + +// Please add Rain interactions with move, item and ability effects on their respective files. +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE); + ASSUME(gBattleMoves[MOVE_WATER_GUN].type == TYPE_WATER); +} + +SINGLE_BATTLE_TEST("Rain multiplies the power of Fire-type moves by 0.5x", s16 damage) +{ + u32 setupMove; + PARAMETRIZE { setupMove = MOVE_CELEBRATE; } + PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, setupMove); } + TURN { MOVE(player, MOVE_EMBER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Rain multiplies the power of Water-type moves by 1.5x", s16 damage) +{ + u32 setupMove; + PARAMETRIZE { setupMove = MOVE_CELEBRATE; } + PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, setupMove); } + TURN { MOVE(player, MOVE_WATER_GUN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} diff --git a/test/weather_sunlight.c b/test/weather_sunlight.c new file mode 100644 index 0000000000..beba0e9b6b --- /dev/null +++ b/test/weather_sunlight.c @@ -0,0 +1,47 @@ +#include "global.h" +#include "test_battle.h" + +// Please add Sunlight interactions with move, item and ability effects on their respective files. +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE); + ASSUME(gBattleMoves[MOVE_WATER_GUN].type == TYPE_WATER); +} + +SINGLE_BATTLE_TEST("Sunlight multiplies the power of Fire-type moves by 1.5x", s16 damage) +{ + u32 setupMove; + PARAMETRIZE { setupMove = MOVE_CELEBRATE; } + PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, setupMove); } + TURN { MOVE(player, MOVE_EMBER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Sunlight multiplies the power of Water-type moves by 0.5x", s16 damage) +{ + u32 setupMove; + PARAMETRIZE { setupMove = MOVE_CELEBRATE; } + PARAMETRIZE { setupMove = MOVE_SUNNY_DAY; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, setupMove); } + TURN { MOVE(player, MOVE_WATER_GUN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +}