From 3ca6792d20e9cce56e04958d449279bbcedb7b37 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 12 May 2026 22:11:59 +0100 Subject: [PATCH 01/59] Minor string-related cleanups --- charmap.txt | 2 +- data/text/mart_clerk.inc | 2 +- src/battle_interface.c | 2 +- src/pokenav_conditions_search_results.c | 4 ++-- src/pokenav_ribbons_list.c | 4 ++-- src/pokenav_ribbons_summary.c | 8 ++++---- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/charmap.txt b/charmap.txt index 477448c9c5..97782f6a97 100644 --- a/charmap.txt +++ b/charmap.txt @@ -406,7 +406,7 @@ B_BUFF3 = FD 34 NAME_END = FC 00 @ special 0xF7 character -DYNAMIC = F7 +DYNAMIC = F7 @ more text functions diff --git a/data/text/mart_clerk.inc b/data/text/mart_clerk.inc index 891fb937e0..859bc1a636 100644 --- a/data/text/mart_clerk.inc +++ b/data/text/mart_clerk.inc @@ -6,5 +6,5 @@ gText_PleaseComeAgain:: .string "Please come again!$" gText_PlayerWhatCanIDoForYou:: - .string "{PLAYER}{STRING 5}, welcome!\p" + .string "{PLAYER}{KUN}, welcome!\p" .string "What can I do for you?$" diff --git a/src/battle_interface.c b/src/battle_interface.c index 5ace9ac158..486b740f9a 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -61,7 +61,7 @@ enum HEALTHBOX_GFX_20, //exp bar [8 pixels] HEALTHBOX_GFX_STATUS_PSN_BATTLER0, //status psn "(P" HEALTHBOX_GFX_22, //status psn "SN" - HEALTHBOX_GFX_23, //status psn "|)"" + HEALTHBOX_GFX_23, //status psn "|)" HEALTHBOX_GFX_STATUS_PRZ_BATTLER0, //status prz HEALTHBOX_GFX_25, HEALTHBOX_GFX_26, diff --git a/src/pokenav_conditions_search_results.c b/src/pokenav_conditions_search_results.c index 5acedc35fe..8646aa9186 100644 --- a/src/pokenav_conditions_search_results.c +++ b/src/pokenav_conditions_search_results.c @@ -125,8 +125,8 @@ static const struct WindowTemplate sSearchResultListMenuWindowTemplate = .baseBlock = 20 }; -static const u8 sText_MaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_RED}{WHITE}{GREEN}♂{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); -static const u8 sText_FemaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_GREEN}{WHITE}{BLUE}♀{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); +static const u8 sText_MaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW LIGHT_RED WHITE GREEN}♂{COLOR_HIGHLIGHT_SHADOW DARK_GRAY WHITE LIGHT_GRAY}"); +static const u8 sText_FemaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW LIGHT_GREEN WHITE BLUE}♀{COLOR_HIGHLIGHT_SHADOW DARK_GRAY WHITE LIGHT_GRAY}"); static const u8 sText_NoGenderSymbol[] = _("{UNK_SPACER}"); bool32 PokenavCallback_Init_ConditionSearch(void) diff --git a/src/pokenav_ribbons_list.c b/src/pokenav_ribbons_list.c index 17233555bf..cdd0fd7201 100644 --- a/src/pokenav_ribbons_list.c +++ b/src/pokenav_ribbons_list.c @@ -120,8 +120,8 @@ static const struct WindowTemplate sRibbonsMonListWindowTemplate = .baseBlock = 20 }; -static const u8 sText_MaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_RED}{WHITE}{GREEN}♂{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); -static const u8 sText_FemaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_GREEN}{WHITE}{BLUE}♀{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); +static const u8 sText_MaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW LIGHT_RED WHITE GREEN}♂{COLOR_HIGHLIGHT_SHADOW DARK_GRAY WHITE LIGHT_GRAY}"); +static const u8 sText_FemaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW LIGHT_GREEN WHITE BLUE}♀{COLOR_HIGHLIGHT_SHADOW DARK_GRAY WHITE LIGHT_GRAY}"); static const u8 sText_NoGenderSymbol[] = _("{UNK_SPACER}"); bool32 PokenavCallback_Init_MonRibbonList(void) diff --git a/src/pokenav_ribbons_summary.c b/src/pokenav_ribbons_summary.c index bfde96374a..b0bf7321f1 100644 --- a/src/pokenav_ribbons_summary.c +++ b/src/pokenav_ribbons_summary.c @@ -865,8 +865,8 @@ static void AddRibbonSummaryMonNameWindow(struct Pokenav_RibbonsSummaryMenu *men PrintRibbbonsSummaryMonInfo(menu); } -static const u8 sMaleIconString[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_RED}{WHITE}{GREEN}♂{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); -static const u8 sFemaleIconString[] = _("{COLOR_HIGHLIGHT_SHADOW}{LIGHT_GREEN}{WHITE}{BLUE}♀{COLOR_HIGHLIGHT_SHADOW}{DARK_GRAY}{WHITE}{LIGHT_GRAY}"); +static const u8 sText_MaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW LIGHT_RED WHITE GREEN}♂{COLOR_HIGHLIGHT_SHADOW DARK_GRAY WHITE LIGHT_GRAY}"); +static const u8 sText_FemaleSymbol[] = _("{COLOR_HIGHLIGHT_SHADOW LIGHT_GREEN WHITE BLUE}♀{COLOR_HIGHLIGHT_SHADOW DARK_GRAY WHITE LIGHT_GRAY}"); static const u8 sGenderlessIconString[] = _("{UNK_SPACER}"); static void PrintRibbbonsSummaryMonInfo(struct Pokenav_RibbonsSummaryMenu *menu) @@ -882,10 +882,10 @@ static void PrintRibbbonsSummaryMonInfo(struct Pokenav_RibbonsSummaryMenu *menu) switch (gender) { case MON_MALE: - genderTxt = sMaleIconString; + genderTxt = sText_MaleSymbol; break; case MON_FEMALE: - genderTxt = sFemaleIconString; + genderTxt = sText_FemaleSymbol; break; default: genderTxt = sGenderlessIconString; From 701c665786d53cfee8185cdc88aaf6f7f0952fd9 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Wed, 13 May 2026 06:19:43 +0100 Subject: [PATCH 02/59] Consistently use '{PAUSE 15}' --- data/text/contest_strings.inc | 64 +++++++++++++++++------------------ data/text/lottery_corner.inc | 2 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/data/text/contest_strings.inc b/data/text/contest_strings.inc index 948c19922d..771799d27c 100644 --- a/data/text/contest_strings.inc +++ b/data/text/contest_strings.inc @@ -263,11 +263,11 @@ gText_MonAppealedWithMove:: gText_MonWasWatchingOthers:: .string "{STR_VAR_1} was watching\n" - .string "the others.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "the others.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_AllOutOfAppealTime:: .string "We're all out of\n" - .string "Appeal Time!{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "Appeal Time!{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" @ Unused appeal result texts @@ -603,121 +603,121 @@ gText_ScrambledUpOrderForNextTurn:: gText_JudgeLookedAtMonExpectantly:: .string "The JUDGE looked at\n" - .string "{STR_VAR_1} expectantly.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "{STR_VAR_1} expectantly.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_AppealComboWentOverWell:: .string "The appeal combo went\n" - .string "over well.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "over well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_AppealComboWentOverVeryWell:: .string "The appeal combo went\n" - .string "over very well.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "over very well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_AppealComboWentOverExcellently:: .string "The appeal combo went\n" - .string "over excellently.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "over excellently.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonManagedToAvertGaze:: .string "{STR_VAR_1} managed to\n" - .string "avert its gaze.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "avert its gaze.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonManagedToAvoidSeeingIt:: .string "{STR_VAR_1} managed to\n" - .string "avoid seeing it.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "avoid seeing it.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonIsntFazedByThatSortOfThing:: .string "{STR_VAR_1} isn't fazed\n" - .string "by that sort of thing.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "by that sort of thing.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonBecameALittleDistracted:: .string "{STR_VAR_1} became a\n" - .string "little distracted.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "little distracted.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_TriedToStartleOtherPokemon:: .string "It tried to startle the\n" - .string "other POKéMON.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "other POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonLookedDownOutOfDistraction:: .string "{STR_VAR_1} looked down\n" - .string "out of distraction.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "out of distraction.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonTurnedBackOutOfDistraction:: .string "{STR_VAR_1} turned back\n" - .string "out of distraction.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "out of distraction.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonCouldntHelpUtteringCry:: .string "{STR_VAR_1} couldn't help\n" - .string "uttering a cry.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "uttering a cry.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonCouldntHelpLeapingUp:: .string "{STR_VAR_1} couldn't help\n" - .string "leaping up.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "leaping up.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonTrippedOutOfDistraction:: .string "{STR_VAR_1} tripped over\n" - .string "out of distraction.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "out of distraction.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonWasTooNervousToMove:: .string "{STR_VAR_1} was too\n" - .string "nervous to move.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "nervous to move.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_ButItMessedUp2:: - .string "But it messed up.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "But it messed up.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_ButItFailedToMakeTargetNervous:: .string "But it failed to make\n" - .string "the target nervous.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "the target nervous.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_ButItFailedToMakeAnyoneNervous:: .string "But it failed to make\n" - .string "anyone nervous.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "anyone nervous.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_ButItWasIgnored:: - .string "But it was ignored…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "But it was ignored…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_CouldntImproveItsCondition:: .string "But it couldn't improve\n" - .string "its condition…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "its condition…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_BadConditionResultedInWeakAppeal:: .string "Its bad condition\n" - .string "resulted in a weak appeal.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "resulted in a weak appeal.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonWasUnaffected:: .string "{STR_VAR_1} was\n" - .string "unaffected.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "unaffected.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_RepeatedAppeal:: .string "{STR_VAR_1} disappointed\n" - .string "by repeating an appeal.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "by repeating an appeal.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonsXWentOverGreat:: .string "{STR_VAR_1}'s {STR_VAR_3}\n" - .string "went over great.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "went over great.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonsXDidntGoOverWell:: .string "{STR_VAR_1}'s {STR_VAR_3}\n" - .string "didn't go over well here…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "didn't go over well here…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonsXGotTheCrowdGoing:: .string "{STR_VAR_1}'s {STR_VAR_3}\n" - .string "got the crowd going.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "got the crowd going.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonCantAppealNextTurn:: .string "{STR_VAR_1} can't appeal\n" - .string "next turn…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "next turn…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_AttractedCrowdsAttention:: .string "It attracted the crowd's\n" - .string "attention.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "attention.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_CrowdContinuesToWatchMon:: .string "The crowd continues to\n" - .string "watch {STR_VAR_3}.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "watch {STR_VAR_3}.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_MonsMoveIsIgnored:: .string "{STR_VAR_1}'s\n" - .string "{STR_VAR_2} is ignored.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "{STR_VAR_2} is ignored.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" gText_Contest_Shyness:: .string "shyness$" diff --git a/data/text/lottery_corner.inc b/data/text/lottery_corner.inc index 44571ef562..e86cdff59c 100644 --- a/data/text/lottery_corner.inc +++ b/data/text/lottery_corner.inc @@ -16,7 +16,7 @@ LilycoveCity_DepartmentStore_1F_Text_PleaseVisitAgain: LilycoveCity_DepartmentStore_1F_Text_PleasePickTicket: .string "Please pick a LOTO TICKET.\n" - .string "…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" LilycoveCity_DepartmentStore_1F_Text_TicketNumberIsXPleaseWait: .string "The LOTO TICKET number is {STR_VAR_1}.\p" From 3960a18c1bb3f1af003757f5c8e8e2ec6e65e10b Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Wed, 13 May 2026 06:28:44 +0100 Subject: [PATCH 03/59] Consistently use decimal for CLEAR and CLEAR_TO --- .../scripts.inc | 16 +-- src/strings.c | 136 +++++++++--------- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/data/maps/Route124_DivingTreasureHuntersHouse/scripts.inc b/data/maps/Route124_DivingTreasureHuntersHouse/scripts.inc index b100438f55..cd5c6c6806 100644 --- a/data/maps/Route124_DivingTreasureHuntersHouse/scripts.inc +++ b/data/maps/Route124_DivingTreasureHuntersHouse/scripts.inc @@ -328,11 +328,11 @@ Route124_DivingTreasureHuntersHouse_Text_ComeBackIfYouChangeMind: .string "Well, if you change your mind, come back.$" Route124_DivingTreasureHuntersHouse_Text_ShardTradeBoard: - .string "{CLEAR_TO 0x0a}Wanted item{CLEAR_TO 0x7c}Trade item\n" - .string "{CLEAR_TO 0x0f}RED SHARD{CLEAR_TO 0x59}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 0x7b}FIRE STONE{CLEAR_TO 0xc8}\p" - .string "{CLEAR_TO 0x0a}Wanted item{CLEAR_TO 0x7c}Trade item\n" - .string "{CLEAR_TO 0x06}YELLOW SHARD{CLEAR_TO 0x59}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 0x73}THUNDERSTONE{CLEAR_TO 0xc8}\p" - .string "{CLEAR_TO 0x0a}Wanted item{CLEAR_TO 0x7c}Trade item\n" - .string "{CLEAR_TO 0x0c}BLUE SHARD{CLEAR_TO 0x59}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 0x79}WATER STONE{CLEAR_TO 0xc8}\p" - .string "{CLEAR_TO 0x0a}Wanted item{CLEAR_TO 0x7c}Trade item\n" - .string "{CLEAR_TO 0x08}GREEN SHARD{CLEAR_TO 0x59}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 0x7b}LEAF STONE$" + .string "{CLEAR_TO 10}Wanted item{CLEAR_TO 124}Trade item\n" + .string "{CLEAR_TO 15}RED SHARD{CLEAR_TO 89}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 123}FIRE STONE{CLEAR_TO 200}\p" + .string "{CLEAR_TO 10}Wanted item{CLEAR_TO 124}Trade item\n" + .string "{CLEAR_TO 6}YELLOW SHARD{CLEAR_TO 89}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 115}THUNDERSTONE{CLEAR_TO 200}\p" + .string "{CLEAR_TO 10}Wanted item{CLEAR_TO 124}Trade item\n" + .string "{CLEAR_TO 12}BLUE SHARD{CLEAR_TO 89}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 121}WATER STONE{CLEAR_TO 200}\p" + .string "{CLEAR_TO 10}Wanted item{CLEAR_TO 124}Trade item\n" + .string "{CLEAR_TO 8}GREEN SHARD{CLEAR_TO 89}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 123}LEAF STONE$" diff --git a/src/strings.c b/src/strings.c index d2a82ada48..4901a8823d 100644 --- a/src/strings.c +++ b/src/strings.c @@ -99,10 +99,10 @@ const u8 gText_DefaultNameLucy[] = _("LUCY"); const u8 gText_DefaultNameHalie[] = _("HALIE"); const u8 gText_ThisIsAPokemon[] = _("This is what we call a “POKéMON.”{PAUSE 96}\p"); const u8 gText_5MarksPokemon[] = _("????? POKéMON"); -const u8 gText_UnkHeight[] = _("{CLEAR_TO 0x0C}??'??”"); +const u8 gText_UnkHeight[] = _("{CLEAR_TO 12}??'??”"); const u8 gText_UnkWeight[] = _("????.? lbs."); const u8 gText_EmptyPkmnCategory[] = _(" POKéMON"); // Unused -const u8 gText_EmptyHeight[] = _("{CLEAR_TO 0x0C} ' ”"); // Unused +const u8 gText_EmptyHeight[] = _("{CLEAR_TO 12} ' ”"); // Unused const u8 gText_EmptyWeight[] = _(" . lbs."); // Unused const u8 gText_EmptyPokedexInfo1[] = _(""); // Unused const u8 gText_CryOf[] = _("CRY OF"); @@ -206,7 +206,7 @@ const u8 gText_ThreeDashes[] = _("---"); const u8 gText_MaleSymbol[] = _("♂"); const u8 gText_FemaleSymbol[] = _("♀"); const u8 gText_LevelSymbol[] = _("{LV}"); -const u8 gText_NumberClear01[] = _("{NO}{CLEAR 0x01}"); +const u8 gText_NumberClear01[] = _("{NO}{CLEAR 1}"); const u8 gText_PlusSymbol[] = _("+"); // Unused const u8 gText_RightArrow[] = _("{RIGHT_ARROW}"); // Unused const u8 gText_IDNumber2[] = _("{ID}{NO}"); @@ -294,8 +294,8 @@ const u8 *const gPocketNamesStringsTable[] = [KEYITEMS_POCKET] = gText_KeyItemsPocket }; -const u8 gText_NumberItem_TMBerry[] = _("{NO}{STR_VAR_1}{CLEAR 0x07}{STR_VAR_2}"); -const u8 gText_NumberItem_HM[] = _("{CLEAR_TO 0x11}{STR_VAR_1}{CLEAR 0x05}{STR_VAR_2}"); +const u8 gText_NumberItem_TMBerry[] = _("{NO}{STR_VAR_1}{CLEAR 7}{STR_VAR_2}"); +const u8 gText_NumberItem_HM[] = _("{CLEAR_TO 17}{STR_VAR_1}{CLEAR 5}{STR_VAR_2}"); const u8 gText_SizeSlash[] = _("SIZE /"); const u8 gText_FirmSlash[] = _("FIRM /"); const u8 gText_Var1DotVar2[] = _("{STR_VAR_1}.{STR_VAR_2}”"); @@ -645,9 +645,9 @@ const u8 gText_Challenge[] = _("CHALLENGE"); const u8 gText_Info3[] = _("INFO"); const u8 gText_Lv50[] = _("LV. 50"); const u8 gText_OpenLevel[] = _("OPEN LEVEL"); -const u8 gText_FreshWaterAndPrice[] = _("FRESH WATER{CLEAR_TO 0x48}¥200"); -const u8 gText_SodaPopAndPrice[] = _("SODA POP{CLEAR_TO 0x48}¥300"); -const u8 gText_LemonadeAndPrice[] = _("LEMONADE{CLEAR_TO 0x48}¥350"); +const u8 gText_FreshWaterAndPrice[] = _("FRESH WATER{CLEAR_TO 72}¥200"); +const u8 gText_SodaPopAndPrice[] = _("SODA POP{CLEAR_TO 72}¥300"); +const u8 gText_LemonadeAndPrice[] = _("LEMONADE{CLEAR_TO 72}¥350"); const u8 gText_HowToRide[] = _("HOW TO RIDE"); const u8 gText_HowToTurn[] = _("HOW TO TURN"); const u8 gText_SandySlopes[] = _("SANDY SLOPES"); @@ -679,11 +679,11 @@ const u8 gText_GreenShard[] = _("GREEN SHARD"); const u8 gText_BattleFrontier[] = _("BATTLE FRONTIER"); const u8 gText_Right[] = _("Right"); const u8 gText_Left[] = _("Left"); -const u8 gText_TM32AndPrice[] = _("TM32{CLEAR_TO 0x48}1,500 COINS"); -const u8 gText_TM29AndPrice[] = _("TM29{CLEAR_TO 0x48}3,500 COINS"); -const u8 gText_TM35AndPrice[] = _("TM35{CLEAR_TO 0x48}4,000 COINS"); -const u8 gText_TM24AndPrice[] = _("TM24{CLEAR_TO 0x48}4,000 COINS"); -const u8 gText_TM13AndPrice[] = _("TM13{CLEAR_TO 0x48}4,000 COINS"); +const u8 gText_TM32AndPrice[] = _("TM32{CLEAR_TO 72}1,500 COINS"); +const u8 gText_TM29AndPrice[] = _("TM29{CLEAR_TO 72}3,500 COINS"); +const u8 gText_TM35AndPrice[] = _("TM35{CLEAR_TO 72}4,000 COINS"); +const u8 gText_TM24AndPrice[] = _("TM24{CLEAR_TO 72}4,000 COINS"); +const u8 gText_TM13AndPrice[] = _("TM13{CLEAR_TO 72}4,000 COINS"); const u8 gText_Cool[] = _("COOL"); const u8 gText_Beauty[] = _("BEAUTY"); const u8 gText_Cute[] = _("CUTE"); @@ -966,7 +966,7 @@ const u8 gText_CantCallOpponentHere[] = _("Can't call opponent here."); // Unuse const u8 gText_PokenavMatchCall_Strategy[] = _("STRATEGY"); const u8 gText_PokenavMatchCall_TrainerPokemon[] = _("TRAINER'S POKéMON"); const u8 gText_PokenavMatchCall_SelfIntroduction[] = _("SELF-INTRODUCTION"); -const u8 gText_Pokenav_ClearButtonList[] = _("{CLEAR 0x80}"); +const u8 gText_Pokenav_ClearButtonList[] = _("{CLEAR 128}"); const u8 gText_PokenavMap_ZoomedOutButtons[] = _("{A_BUTTON}ZOOM {B_BUTTON}CANCEL"); const u8 gText_PokenavMap_ZoomedInButtons[] = _("{A_BUTTON}FULL {B_BUTTON}CANCEL"); const u8 gText_PokenavCondition_MonListButtons[] = _("{A_BUTTON}CONDITION {B_BUTTON}CANCEL"); @@ -1136,56 +1136,56 @@ const u8 gText_80Pts[] = _("80 pts"); const u8 gText_90Pts[] = _("90 pts"); const u8 gText_100Pts[] = _("100 pts"); const u8 gText_QuestionMark[] = _("?"); -const u8 gText_KissPoster16BP[] = _("KISS POSTER{CLEAR_TO 0x5E}16BP"); -const u8 gText_KissCushion32BP[] = _("KISS CUSHION{CLEAR_TO 0x5E}32BP"); -const u8 gText_SmoochumDoll32BP[] = _("SMOOCHUM DOLL{CLEAR_TO 0x5E}32BP"); -const u8 gText_TogepiDoll48BP[] = _("TOGEPI DOLL{CLEAR_TO 0x5E}48BP"); -const u8 gText_MeowthDoll48BP[] = _("MEOWTH DOLL{CLEAR_TO 0x5E}48BP"); -const u8 gText_ClefairyDoll48BP[] = _("CLEFAIRY DOLL{CLEAR_TO 0x5E}48BP"); -const u8 gText_DittoDoll48BP[] = _("DITTO DOLL{CLEAR_TO 0x5E}48BP"); -const u8 gText_CyndaquilDoll80BP[] = _("CYNDAQUIL DOLL{CLEAR_TO 0x5E}80BP"); -const u8 gText_ChikoritaDoll80BP[] = _("CHIKORITA DOLL{CLEAR_TO 0x5E}80BP"); -const u8 gText_TotodileDoll80BP[] = _("TOTODILE DOLL{CLEAR_TO 0x5E}80BP"); -const u8 gText_LaprasDoll128BP[] = _("LAPRAS DOLL{CLEAR_TO 0x58}128BP"); -const u8 gText_SnorlaxDoll128BP[] = _("SNORLAX DOLL{CLEAR_TO 0x58}128BP"); -const u8 gText_VenusaurDoll256BP[] = _("VENUSAUR DOLL{CLEAR_TO 0x58}256BP"); -const u8 gText_CharizardDoll256BP[] = _("CHARIZARD DOLL{CLEAR_TO 0x58}256BP"); -const u8 gText_BlastoiseDoll256BP[] = _("BLASTOISE DOLL{CLEAR_TO 0x58}256BP"); -const u8 gText_Protein1BP[] = _("PROTEIN{CLEAR_TO 0x64}1BP"); -const u8 gText_Calcium1BP[] = _("CALCIUM{CLEAR_TO 0x64}1BP"); -const u8 gText_Iron1BP[] = _("IRON{CLEAR_TO 0x64}1BP"); -const u8 gText_Zinc1BP[] = _("ZINC{CLEAR_TO 0x64}1BP"); -const u8 gText_Carbos1BP[] = _("CARBOS{CLEAR_TO 0x64}1BP"); -const u8 gText_HpUp1BP[] = _("HP UP{CLEAR_TO 0x64}1BP"); -const u8 gText_Leftovers48BP[] = _("LEFTOVERS{CLEAR_TO 0x5E}48BP"); -const u8 gText_WhiteHerb48BP[] = _("WHITE HERB{CLEAR_TO 0x5E}48BP"); -const u8 gText_QuickClaw48BP[] = _("QUICK CLAW{CLEAR_TO 0x5E}48BP"); -const u8 gText_MentalHerb48BP[] = _("MENTAL HERB{CLEAR_TO 0x5E}48BP"); -const u8 gText_BrightPowder64BP[] = _("BRIGHTPOWDER{CLEAR_TO 0x5E}64BP"); -const u8 gText_ChoiceBand64BP[] = _("CHOICE BAND{CLEAR_TO 0x5E}64BP"); -const u8 gText_KingsRock64BP[] = _("KING'S ROCK{CLEAR_TO 0x5E}64BP"); -const u8 gText_FocusBand64BP[] = _("FOCUS BAND{CLEAR_TO 0x5E}64BP"); -const u8 gText_ScopeLens64BP[] = _("SCOPE LENS{CLEAR_TO 0x5E}64BP"); -const u8 gText_Softboiled16BP[] = _("SOFTBOILED{CLEAR_TO 0x4E}16BP"); -const u8 gText_SeismicToss24BP[] = _("SEISMIC TOSS{CLEAR_TO 0x4E}24BP"); -const u8 gText_DreamEater24BP[] = _("DREAM EATER{CLEAR_TO 0x4E}24BP"); -const u8 gText_MegaPunch24BP[] = _("MEGA PUNCH{CLEAR_TO 0x4E}24BP"); -const u8 gText_MegaKick48BP[] = _("MEGA KICK{CLEAR_TO 0x4E}48BP"); -const u8 gText_BodySlam48BP[] = _("BODY SLAM{CLEAR_TO 0x4E}48BP"); -const u8 gText_RockSlide48BP[] = _("ROCK SLIDE{CLEAR_TO 0x4E}48BP"); -const u8 gText_Counter48BP[] = _("COUNTER{CLEAR_TO 0x4E}48BP"); -const u8 gText_ThunderWave48BP[] = _("THUNDER WAVE{CLEAR_TO 0x4E}48BP"); -const u8 gText_SwordsDance48BP[] = _("SWORDS DANCE{CLEAR_TO 0x4E}48BP"); -const u8 gText_DefenseCurl16BP[] = _("DEFENSE CURL{CLEAR_TO 0x4E}16BP"); -const u8 gText_Snore24BP[] = _("SNORE{CLEAR_TO 0x4E}24BP"); -const u8 gText_MudSlap24BP[] = _("MUD-SLAP{CLEAR_TO 0x4E}24BP"); -const u8 gText_Swift24BP[] = _("SWIFT{CLEAR_TO 0x4E}24BP"); -const u8 gText_IcyWind24BP[] = _("ICY WIND{CLEAR_TO 0x4E}24BP"); -const u8 gText_Endure48BP[] = _("ENDURE{CLEAR_TO 0x4E}48BP"); -const u8 gText_PsychUp48BP[] = _("PSYCH UP{CLEAR_TO 0x4E}48BP"); -const u8 gText_IcePunch48BP[] = _("ICE PUNCH{CLEAR_TO 0x4E}48BP"); -const u8 gText_ThunderPunch48BP[] = _("THUNDERPUNCH{CLEAR_TO 0x4E}48BP"); -const u8 gText_FirePunch48BP[] = _("FIRE PUNCH{CLEAR_TO 0x4E}48BP"); +const u8 gText_KissPoster16BP[] = _("KISS POSTER{CLEAR_TO 94}16BP"); +const u8 gText_KissCushion32BP[] = _("KISS CUSHION{CLEAR_TO 94}32BP"); +const u8 gText_SmoochumDoll32BP[] = _("SMOOCHUM DOLL{CLEAR_TO 94}32BP"); +const u8 gText_TogepiDoll48BP[] = _("TOGEPI DOLL{CLEAR_TO 94}48BP"); +const u8 gText_MeowthDoll48BP[] = _("MEOWTH DOLL{CLEAR_TO 94}48BP"); +const u8 gText_ClefairyDoll48BP[] = _("CLEFAIRY DOLL{CLEAR_TO 94}48BP"); +const u8 gText_DittoDoll48BP[] = _("DITTO DOLL{CLEAR_TO 94}48BP"); +const u8 gText_CyndaquilDoll80BP[] = _("CYNDAQUIL DOLL{CLEAR_TO 94}80BP"); +const u8 gText_ChikoritaDoll80BP[] = _("CHIKORITA DOLL{CLEAR_TO 94}80BP"); +const u8 gText_TotodileDoll80BP[] = _("TOTODILE DOLL{CLEAR_TO 94}80BP"); +const u8 gText_LaprasDoll128BP[] = _("LAPRAS DOLL{CLEAR_TO 88}128BP"); +const u8 gText_SnorlaxDoll128BP[] = _("SNORLAX DOLL{CLEAR_TO 88}128BP"); +const u8 gText_VenusaurDoll256BP[] = _("VENUSAUR DOLL{CLEAR_TO 88}256BP"); +const u8 gText_CharizardDoll256BP[] = _("CHARIZARD DOLL{CLEAR_TO 88}256BP"); +const u8 gText_BlastoiseDoll256BP[] = _("BLASTOISE DOLL{CLEAR_TO 88}256BP"); +const u8 gText_Protein1BP[] = _("PROTEIN{CLEAR_TO 100}1BP"); +const u8 gText_Calcium1BP[] = _("CALCIUM{CLEAR_TO 100}1BP"); +const u8 gText_Iron1BP[] = _("IRON{CLEAR_TO 100}1BP"); +const u8 gText_Zinc1BP[] = _("ZINC{CLEAR_TO 100}1BP"); +const u8 gText_Carbos1BP[] = _("CARBOS{CLEAR_TO 100}1BP"); +const u8 gText_HpUp1BP[] = _("HP UP{CLEAR_TO 100}1BP"); +const u8 gText_Leftovers48BP[] = _("LEFTOVERS{CLEAR_TO 94}48BP"); +const u8 gText_WhiteHerb48BP[] = _("WHITE HERB{CLEAR_TO 94}48BP"); +const u8 gText_QuickClaw48BP[] = _("QUICK CLAW{CLEAR_TO 94}48BP"); +const u8 gText_MentalHerb48BP[] = _("MENTAL HERB{CLEAR_TO 94}48BP"); +const u8 gText_BrightPowder64BP[] = _("BRIGHTPOWDER{CLEAR_TO 94}64BP"); +const u8 gText_ChoiceBand64BP[] = _("CHOICE BAND{CLEAR_TO 94}64BP"); +const u8 gText_KingsRock64BP[] = _("KING'S ROCK{CLEAR_TO 94}64BP"); +const u8 gText_FocusBand64BP[] = _("FOCUS BAND{CLEAR_TO 94}64BP"); +const u8 gText_ScopeLens64BP[] = _("SCOPE LENS{CLEAR_TO 94}64BP"); +const u8 gText_Softboiled16BP[] = _("SOFTBOILED{CLEAR_TO 78}16BP"); +const u8 gText_SeismicToss24BP[] = _("SEISMIC TOSS{CLEAR_TO 78}24BP"); +const u8 gText_DreamEater24BP[] = _("DREAM EATER{CLEAR_TO 78}24BP"); +const u8 gText_MegaPunch24BP[] = _("MEGA PUNCH{CLEAR_TO 78}24BP"); +const u8 gText_MegaKick48BP[] = _("MEGA KICK{CLEAR_TO 78}48BP"); +const u8 gText_BodySlam48BP[] = _("BODY SLAM{CLEAR_TO 78}48BP"); +const u8 gText_RockSlide48BP[] = _("ROCK SLIDE{CLEAR_TO 78}48BP"); +const u8 gText_Counter48BP[] = _("COUNTER{CLEAR_TO 78}48BP"); +const u8 gText_ThunderWave48BP[] = _("THUNDER WAVE{CLEAR_TO 78}48BP"); +const u8 gText_SwordsDance48BP[] = _("SWORDS DANCE{CLEAR_TO 78}48BP"); +const u8 gText_DefenseCurl16BP[] = _("DEFENSE CURL{CLEAR_TO 78}16BP"); +const u8 gText_Snore24BP[] = _("SNORE{CLEAR_TO 78}24BP"); +const u8 gText_MudSlap24BP[] = _("MUD-SLAP{CLEAR_TO 78}24BP"); +const u8 gText_Swift24BP[] = _("SWIFT{CLEAR_TO 78}24BP"); +const u8 gText_IcyWind24BP[] = _("ICY WIND{CLEAR_TO 78}24BP"); +const u8 gText_Endure48BP[] = _("ENDURE{CLEAR_TO 78}48BP"); +const u8 gText_PsychUp48BP[] = _("PSYCH UP{CLEAR_TO 78}48BP"); +const u8 gText_IcePunch48BP[] = _("ICE PUNCH{CLEAR_TO 78}48BP"); +const u8 gText_ThunderPunch48BP[] = _("THUNDERPUNCH{CLEAR_TO 78}48BP"); +const u8 gText_FirePunch48BP[] = _("FIRE PUNCH{CLEAR_TO 78}48BP"); const u8 gText_PkmnFainted_FldPsn[] = _("{STR_VAR_1} fainted…\p\n"); const u8 gText_Marco[] = _("MARCO"); const u8 gText_TrainerCardName[] = _("NAME: "); @@ -1369,7 +1369,7 @@ const u8 gText_BerriesPicked[] = _("BERRIES picked:"); const u8 gText_BestScore[] = _("Best score:"); const u8 gText_BerriesInRowFivePlayers[] = _("BERRIES picked in a row with\nfive players:"); const u8 gText_BerryPickingResults[] = _("Announcing BERRY-PICKING results!"); -const u8 gText_10P30P50P50P[] = _("{CLEAR_TO 0x03}10P{CLEAR_TO 0x2B}30P{CLEAR_TO 0x53}50P{CLEAR_TO 0x77}{EMOJI_MINUS}50P"); +const u8 gText_10P30P50P50P[] = _("{CLEAR_TO 3}10P{CLEAR_TO 43}30P{CLEAR_TO 83}50P{CLEAR_TO 119}{EMOJI_MINUS}50P"); const u8 gText_AnnouncingRankings[] = _("Announcing rankings!"); const u8 gText_AnnouncingPrizes[] = _("Announcing prizes!"); const u8 gText_1Colon[] = _("1:"); @@ -1447,7 +1447,7 @@ const u8 gText_Total[] = _("Total"); const u8 gText_ClearStreak[] = _("Clear streak: {STR_VAR_1}"); const u8 gText_Championships[] = _("Championships: {STR_VAR_1}"); const u8 gText_RoomsCleared[] = _("Rooms cleared: {STR_VAR_1}"); -const u8 gText_TimesCleared[] = _("Times cleared:{CLEAR 0x05}{STR_VAR_1}"); +const u8 gText_TimesCleared[] = _("Times cleared:{CLEAR 5}{STR_VAR_1}"); const u8 gText_KOsInARow[] = _("KOs in a row: {STR_VAR_1}"); const u8 gText_TimesVar1[] = _("Times: {STR_VAR_1}"); const u8 gText_FloorsCleared[] = _("Floors cleared: {STR_VAR_1}"); @@ -1537,7 +1537,7 @@ const u8 gJPText_Player[] = _("プレイヤー"); // Unused const u8 gJPText_Sama[] = _("さま"); // Unused const u8 gText_DexHoenn[] = _("HOENN"); const u8 gText_DexNational[] = _("NATIONAL"); -const u8 gText_PokedexDiploma[] = _("PLAYER: {CLEAR 0x10}{COLOR RED}{SHADOW LIGHT_RED}{PLAYER}{COLOR DARK_GRAY}{SHADOW LIGHT_GRAY}\n\nThis document certifies\nthat you have successfully\ncompleted your\n{STR_VAR_1} POKéDEX.\n\n{CLEAR_TO 0x42}{COLOR RED}{SHADOW LIGHT_RED}GAME FREAK"); +const u8 gText_PokedexDiploma[] = _("PLAYER: {CLEAR 16}{COLOR RED}{SHADOW LIGHT_RED}{PLAYER}{COLOR DARK_GRAY}{SHADOW LIGHT_GRAY}\n\nThis document certifies\nthat you have successfully\ncompleted your\n{STR_VAR_1} POKéDEX.\n\n{CLEAR_TO 66}{COLOR RED}{SHADOW LIGHT_RED}GAME FREAK"); const u8 gJPText_GameFreak[] = _("{COLOR RED}{SHADOW LIGHT_RED}ゲ-ムフリ-ク"); // Unused const u8 gText_DiplomaEmpty[] = _("{COLOR RED}{SHADOW LIGHT_RED}"); // Unused const u8 gText_Hoenn[] = _("HOENN"); @@ -1721,7 +1721,7 @@ ALIGNED(4) const u8 gText_PickOKExit[] = _("{DPAD_UPDOWN}PICK {A_BUTTON}OK {B_BU ALIGNED(4) const u8 gText_PickOKCancel[] = _("{DPAD_UPDOWN}PICK {A_BUTTON}OK {B_BUTTON}CANCEL"); const u8 gText_PlayersBattleResults[] = _("{PLAYER}'s BATTLE RESULTS"); const u8 gText_TotalRecordWLD[] = _("TOTAL RECORD W:{STR_VAR_1} L:{STR_VAR_2} D:{STR_VAR_3}"); -const u8 gText_WinLoseDraw[] = _("{CLEAR_TO 0x53}WIN{CLEAR_TO 0x80}LOSE{CLEAR_TO 0xB0}DRAW"); +const u8 gText_WinLoseDraw[] = _("{CLEAR_TO 83}WIN{CLEAR_TO 128}LOSE{CLEAR_TO 176}DRAW"); const u8 gText_CommunicationStandby5[] = _("Communication standby…"); const u8 gText_QuitTheGame[] = _("Quit the game?"); const u8 gText_YouveGot9999Coins[] = _("You've got 9,999 COINS."); From 0d3100185e0b13faabfc589fc402dd46f83c1d6a Mon Sep 17 00:00:00 2001 From: FosterProgramming Date: Sat, 16 May 2026 03:51:57 +0200 Subject: [PATCH 04/59] Rename mass outbreak show to distinguish from savefile outbreakDaysLeft (#2288) --- include/global.tv.h | 2 +- src/tv.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/global.tv.h b/include/global.tv.h index a2721b06b4..4fac792cb8 100644 --- a/include/global.tv.h +++ b/include/global.tv.h @@ -486,7 +486,7 @@ typedef union // size = 0x24 /*0x13*/ u8 probability; /*0x14*/ u8 level; /*0x15*/ u8 unused5; - /*0x16*/ u16 daysLeft; + /*0x16*/ u16 daysBeforeOutbreak; /*0x18*/ u8 language; /*0x19*/ //u8 padding; } massOutbreak; diff --git a/src/tv.c b/src/tv.c index 8f4de5548e..29e1a15f0f 100644 --- a/src/tv.c +++ b/src/tv.c @@ -137,7 +137,7 @@ static void TryPutPokemonTodayFailedOnTheAir(void); static void TryStartRandomMassOutbreak(void); static void TryPutRandomPokeNewsOnAir(void); static void SortPurchasesByQuantity(void); -static void UpdateMassOutbreakTimeLeft(u16); +static void UpdateTimeBeforeMassOutbreak(u16); static void TryEndMassOutbreak(u16); static void UpdatePokeNewsCountdown(u16); static void ResolveWorldOfMastersShow(u16); @@ -797,7 +797,7 @@ u8 GetRandomActiveShowIdx(void) else { show = &gSaveBlock1Ptr->tvShows[j]; - if (show->massOutbreak.daysLeft == 0 && show->massOutbreak.active == TRUE) + if (show->massOutbreak.daysBeforeOutbreak == 0 && show->massOutbreak.active == TRUE) return j; } @@ -1679,7 +1679,7 @@ static void TryStartRandomMassOutbreak(void) show->massOutbreak.unused4 = 0; show->massOutbreak.probability = 50; show->massOutbreak.unused5 = 0; - show->massOutbreak.daysLeft = 1; + show->massOutbreak.daysBeforeOutbreak = 1; StorePlayerIdInNormalShow(show); show->massOutbreak.language = gGameLanguage; } @@ -1706,14 +1706,14 @@ void EndMassOutbreak(void) void UpdateTVShowsPerDay(u16 days) { - UpdateMassOutbreakTimeLeft(days); + UpdateTimeBeforeMassOutbreak(days); TryEndMassOutbreak(days); UpdatePokeNewsCountdown(days); ResolveWorldOfMastersShow(days); ResolveNumberOneShow(days); } -static void UpdateMassOutbreakTimeLeft(u16 days) +static void UpdateTimeBeforeMassOutbreak(u16 days) { u8 i; TVShow *show; @@ -1725,10 +1725,10 @@ static void UpdateMassOutbreakTimeLeft(u16 days) if (gSaveBlock1Ptr->tvShows[i].massOutbreak.kind == TVSHOW_MASS_OUTBREAK && gSaveBlock1Ptr->tvShows[i].massOutbreak.active == TRUE) { show = &gSaveBlock1Ptr->tvShows[i]; - if (show->massOutbreak.daysLeft < days) - show->massOutbreak.daysLeft = 0; + if (show->massOutbreak.daysBeforeOutbreak < days) + show->massOutbreak.daysBeforeOutbreak = 0; else - show->massOutbreak.daysLeft -= days; + show->massOutbreak.daysBeforeOutbreak -= days; break; } @@ -3619,7 +3619,7 @@ static bool8 TryMixOutbreakTVShow(TVShow *dest, TVShow *src, u8 idx) src->common.srcTrainerIdHi = linkTrainerId >> 8; *dest = *src; dest->common.active = TRUE; - dest->massOutbreak.daysLeft = 1; + dest->massOutbreak.daysBeforeOutbreak = 1; return TRUE; } From 2d29864375a9a43c9c5f00555822fd7e5bc1e01f Mon Sep 17 00:00:00 2001 From: William Jackson Date: Wed, 27 May 2026 17:14:19 +0100 Subject: [PATCH 05/59] Bugfix: ensure move is correctly read (#2297) --- src/battle_ai_script_commands.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index c3658da89f..5cb0a60a6d 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -1803,7 +1803,13 @@ static void Cmd_if_cant_faint(void) static void Cmd_if_has_move(void) { s32 i; + +#ifdef BUGFIX + const u16 move = T1_READ_16(gAIScriptPtr + 2); + const u16 *movePtr = &move; +#else const u16 *movePtr = (u16 *)(gAIScriptPtr + 2); +#endif switch (gAIScriptPtr[1]) { @@ -1855,7 +1861,13 @@ static void Cmd_if_has_move(void) static void Cmd_if_doesnt_have_move(void) { s32 i; + +#ifdef BUGFIX + const u16 move = T1_READ_16(gAIScriptPtr + 2); + const u16 *movePtr = &move; +#else const u16 *movePtr = (u16 *)(gAIScriptPtr + 2); +#endif switch(gAIScriptPtr[1]) { From c46e53bd020eccb91acb90fdff42a0a5c47ddb14 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 28 Apr 2026 17:07:26 +0100 Subject: [PATCH 06/59] Fix typos in event scripts --- .../BattleFrontier_BattleTowerMultiPartnerRoom/scripts.inc | 4 ++-- data/maps/MtChimney/scripts.inc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/maps/BattleFrontier_BattleTowerMultiPartnerRoom/scripts.inc b/data/maps/BattleFrontier_BattleTowerMultiPartnerRoom/scripts.inc index 6cd428c8ed..920f912a9e 100644 --- a/data/maps/BattleFrontier_BattleTowerMultiPartnerRoom/scripts.inc +++ b/data/maps/BattleFrontier_BattleTowerMultiPartnerRoom/scripts.inc @@ -126,7 +126,7 @@ BattleFrontier_BattleTowerMultiPartnerRoom_EventScript_MoveToElevatorEast: @ Unused BattleFrontier_BattleTowerMultiPartnerRoom_EventScript_MoveToElevatorWest: applymovement LOCALID_TOWER_PARTNER_ROOM_ATTENDANT, BattleFrontier_BattleTowerMultiPartnerRoom_Movement_AttendantEnterElevator - applymovement LOCALID_PLAYER, BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEneterElevatorWest + applymovement LOCALID_PLAYER, BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEnterElevatorWest waitmovement 0 return @@ -144,7 +144,7 @@ BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEnterElevatorEast: step_end @ Functionally unused -BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEneterElevatorWest: +BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEnterElevatorWest: walk_left walk_up set_invisible diff --git a/data/maps/MtChimney/scripts.inc b/data/maps/MtChimney/scripts.inc index 9d9e1d4eae..ff20292335 100644 --- a/data/maps/MtChimney/scripts.inc +++ b/data/maps/MtChimney/scripts.inc @@ -456,7 +456,7 @@ MtChimney_EventScript_MachineOff:: end MtChimney_EventScript_MachineOn:: - msgbox MtChimney_Text_MetoriteFittedOnMachine, MSGBOX_DEFAULT + msgbox MtChimney_Text_MeteoriteFittedOnMachine, MSGBOX_DEFAULT releaseall end @@ -711,7 +711,7 @@ MtChimney_Text_YouveNotGotTheMoney: MtChimney_Text_OhFineThen: .string "Oh, fine then.$" -MtChimney_Text_MetoriteFittedOnMachine: +MtChimney_Text_MeteoriteFittedOnMachine: .string "A METEORITE is fitted on a mysterious\n" .string "machine…\p" .string "The machine seems to be storing\n" From 5f7ebb03bd54d0422409d66eb92d2cae9c00f174 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sat, 30 May 2026 20:50:50 +0200 Subject: [PATCH 07/59] Fixes stat change queue having erroneous stats stored (#10088) --- include/battle_stat_change.h | 1 + src/battle_stat_change.c | 14 +++++++++ src/battle_util.c | 22 +++++++------ test/battle/stat_change_leaks.c | 55 +++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 test/battle/stat_change_leaks.c diff --git a/include/battle_stat_change.h b/include/battle_stat_change.h index ea4d2d4911..67a805747b 100644 --- a/include/battle_stat_change.h +++ b/include/battle_stat_change.h @@ -39,6 +39,7 @@ void SetStatChange(enum BattlerId battler, enum Stat stat, s32 stage); void SetStatChange2(enum BattlerId battler, enum Stat stat, s32 stage); void ClearStatChangeValues(void); void ClearOtherStatChangeValues(enum BattlerId battler); +void ClearBothStatChangeQueues(void); enum StatChangeResult TrySingleStatChange(struct BattleCalcValues *cv, struct StatChange *st); u32 GetStatStage(u32 stat, const struct AdditionalEffect *additionalEffect); diff --git a/src/battle_stat_change.c b/src/battle_stat_change.c index 66760a8e63..5a9193acc6 100644 --- a/src/battle_stat_change.c +++ b/src/battle_stat_change.c @@ -926,6 +926,20 @@ void ClearOtherStatChangeValues(enum BattlerId battler) gBattleStruct->positiveAnimPlayed = 0; } +void ClearBothStatChangeQueues(void) +{ + for (enum BattlerId battler = 0; battler < gBattlersCount; battler++) + { + memset(gSpecialStatuses[battler].statStageQueue2, 0, sizeof(gSpecialStatuses[battler].statStageQueue2)); + gSpecialStatuses[battler].statStageAmount2 = 0; + memset(gSpecialStatuses[battler].statStageQueue, 0, sizeof(gSpecialStatuses[battler].statStageQueue)); + gSpecialStatuses[battler].statStageAmount = 0; + } + gBattleStruct->negativeAnimPlayed = 0; + gBattleStruct->positiveAnimPlayed = 0; + gBattleStruct->statChangeBattler = 0; +} + bool32 CompareStat(enum BattlerId battler, enum Stat statId, u32 cmpTo, u32 cmpKind, enum Ability ability) { bool32 ret = FALSE; diff --git a/src/battle_util.c b/src/battle_util.c index f622f7c0e5..9a59a37e35 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -66,7 +66,7 @@ static void ResetParadoxTerrainStat(enum BattlerId battler); static bool32 CanBattlerFormChange(enum BattlerId battler, enum FormChanges method); static bool32 IsPowderMoveBlocked(struct DamageContext *ctx); const u8 *AbsorbedByDrainHpAbility(enum BattlerId battlerDef); -const u8 *AbsorbedByStatIncreaseAbility(enum BattlerId battlerDef, enum Ability abilityDef, enum Stat statId, u32 statAmount); +const u8 *AbsorbedByStatIncreaseAbility(struct DamageContext *ctx, enum Stat statId, u32 statAmount); const u8 *AbsorbedByFlashFire(enum BattlerId battlerDef); static bool32 IsCriticalHit(struct DamageContext *ctx); @@ -448,6 +448,7 @@ void HandleAction_UseMove(void) gBattleStruct->eventState.atkCanceler = 0; ClearDamageCalcResults(); + ClearBothStatChangeQueues(); gMultiHitCounter = 0; gBattleCommunication[MISS_TYPE] = 0; gBattlerTarget = gBattleStruct->moveTarget[gBattlerAttacker]; @@ -2255,27 +2256,27 @@ bool32 CanAbilityAbsorbMove(struct DamageContext *ctx) break; case ABILITY_MOTOR_DRIVE: if (ctx->moveType == TYPE_ELECTRIC) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_SPEED, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_SPEED, 1); break; case ABILITY_LIGHTNING_ROD: if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && ctx->moveType == TYPE_ELECTRIC) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_SPATK, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_SPATK, 1); break; case ABILITY_STORM_DRAIN: if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && ctx->moveType == TYPE_WATER) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_SPATK, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_SPATK, 1); break; case ABILITY_SAP_SIPPER: if (ctx->moveType == TYPE_GRASS) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_ATK, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_ATK, 1); break; case ABILITY_WELL_BAKED_BODY: if (ctx->moveType == TYPE_FIRE) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_DEF, 2); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_DEF, 2); break; case ABILITY_WIND_RIDER: if (IsWindMove(ctx->move)) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_ATK, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_ATK, 1); break; case ABILITY_FLASH_FIRE: if (ctx->moveType == TYPE_FIRE && (B_FLASH_FIRE_FROZEN >= GEN_5 || !(gBattleMons[ctx->battlerDef].status1 & STATUS1_FREEZE))) @@ -2327,15 +2328,16 @@ const u8 *AbsorbedByDrainHpAbility(enum BattlerId battlerDef) } } -const u8 *AbsorbedByStatIncreaseAbility(enum BattlerId battlerDef, enum Ability abilityDef, enum Stat statId, u32 statAmount) +const u8 *AbsorbedByStatIncreaseAbility(struct DamageContext *ctx, enum Stat statId, u32 statAmount) { - if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, abilityDef)) + if (!CompareStat(ctx->battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, ctx->abilities[ctx->battlerDef])) { return BattleScript_AbilityProtectedTarget; } else { - SetStatChange(battlerDef, statId, statAmount); + if (ctx->runScript) + SetStatChange(ctx->battlerDef, statId, statAmount); return BattleScript_MoveStatDrain; } } diff --git a/test/battle/stat_change_leaks.c b/test/battle/stat_change_leaks.c new file mode 100644 index 0000000000..51ff94ba08 --- /dev/null +++ b/test/battle/stat_change_leaks.c @@ -0,0 +1,55 @@ +#include "global.h" +#include "test/battle.h" + +AI_SINGLE_BATTLE_TEST("Type-absorbing ability checks don't queue stat increases") +{ + enum Ability ability; + enum Move absorbedMove; + enum Species species; + enum Stat boostedStat; + + PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_STORM_DRAIN; absorbedMove = MOVE_WATER_GUN; boostedStat = STAT_SPATK; } + PARAMETRIZE { species = SPECIES_RAICHU; ability = ABILITY_LIGHTNING_ROD; absorbedMove = MOVE_THUNDERBOLT; boostedStat = STAT_SPATK; } + PARAMETRIZE { species = SPECIES_MARILL; ability = ABILITY_SAP_SIPPER; absorbedMove = MOVE_VINE_WHIP; boostedStat = STAT_ATK; } + + GIVEN { + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); + ASSUME_STAT_CHANGE(MOVE_GROWL, attack: -1); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(species) { Ability(ability); Speed(1); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(absorbedMove, MOVE_GROWL); Speed(2); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_GROWL); } + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1); + if (boostedStat != STAT_ATK) + EXPECT_EQ(player->statStages[boostedStat], DEFAULT_STAT_STAGE); + } +} + +AI_SINGLE_BATTLE_TEST("Type-absorbing abilities only increase a stat once after AI checks") +{ + enum Ability ability; + enum Move absorbedMove; + enum Species species; + enum Stat boostedStat; + + PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_STORM_DRAIN; absorbedMove = MOVE_WATER_GUN; boostedStat = STAT_SPATK; } + PARAMETRIZE { species = SPECIES_RAICHU; ability = ABILITY_LIGHTNING_ROD; absorbedMove = MOVE_THUNDERBOLT; boostedStat = STAT_SPATK; } + PARAMETRIZE { species = SPECIES_MARILL; ability = ABILITY_SAP_SIPPER; absorbedMove = MOVE_VINE_WHIP; boostedStat = STAT_ATK; } + + GIVEN { + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(species) { Ability(ability); Speed(1); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(absorbedMove); Speed(2); } + } WHEN { + TURN { EXPECT_MOVE(opponent, absorbedMove); } + } THEN { + EXPECT_EQ(player->statStages[boostedStat], DEFAULT_STAT_STAGE + 1); + } +} From 6b54a25997b179733b802c3ee21962bd8428e478 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sun, 31 May 2026 09:50:43 +0200 Subject: [PATCH 08/59] Fixes Acupressure timeout in doubles (#10091) --- src/battle_move_resolution.c | 71 ++++++++-------- test/battle/move_effect/acupressure.c | 115 ++++++++++++++++++++++++-- 2 files changed, 143 insertions(+), 43 deletions(-) diff --git a/src/battle_move_resolution.c b/src/battle_move_resolution.c index 32e43e2e7c..0dc806bfa0 100644 --- a/src/battle_move_resolution.c +++ b/src/battle_move_resolution.c @@ -722,13 +722,11 @@ static bool32 IsTargetingSelfOrAlly(enum BattlerId battlerAtk, enum BattlerId ba if (battlerDef == battlerAtk) return skipFailure; - if (battlerDef != BATTLE_PARTNER(battlerAtk)) - { - gBattleStruct->moveResultFlags[battlerDef] = MOVE_RESULT_DOESNT_AFFECT_FOE; - return skipFailure; - } + if (battlerDef == gBattlerTarget) + return checkFailure; - return checkFailure; + gBattleStruct->moveResultFlags[battlerDef] = MOVE_RESULT_DOESNT_AFFECT_FOE; + return skipFailure; } static bool32 IsTargetingFoesAndAlly(enum BattlerId battlerAtk, enum BattlerId battlerDef) @@ -4483,10 +4481,43 @@ static enum MoveResult StatChangeSubstitute(struct BattleCalcValues *cv) return MOVE_RESULT_CONTINUE; } +static void TryAcupressureStatChange(struct BattleCalcValues *cv) +{ + u32 bits = 0; + + if (ShouldSkipStatChangeOnBattler(cv->battlerAtk, cv->battlerDef)) + return; + + for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) + { + if (CompareStat(cv->battlerDef, stat, MAX_STAT_STAGE, CMP_LESS_THAN, cv->abilities[cv->battlerDef])) + bits |= 1u << stat; + } + + if (bits) + { + enum Stat statId; + do + { + statId = (Random() % (NUM_BATTLE_STATS - 1)) + 1; + } while (!(bits & (1u << statId))); + + SetStatChange(cv->battlerDef, statId, 2); + gBattleStruct->moveResultFlags[cv->battlerDef] = MOVE_RESULT_ATTEMPT_STAT_CHANGE; + } + else + { + gBattleStruct->moveResultFlags[cv->battlerDef] = MOVE_RESULT_DOESNT_AFFECT_FOE; + } +} + static enum MoveResult StatChangeCanAnyChange(struct BattleCalcValues *cv) { if (GetMoveEffect(cv->move) == EFFECT_ACUPRESSURE) + { + TryAcupressureStatChange(cv); return MOVE_RESULT_CONTINUE; + } struct StatChange st = { .onlyChecking = TRUE, @@ -4574,34 +4605,6 @@ static enum MoveResult StatChangeBeforeChange(struct BattleCalcValues *cv) return MOVE_RESULT_RUN_SCRIPT_INCREMENT; } break; - case EFFECT_ACUPRESSURE: - { - u32 bits = 0; - for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) - { - if (CompareStat(cv->battlerDef, stat, MAX_STAT_STAGE, CMP_LESS_THAN, cv->abilities[cv->battlerDef])) - bits |= 1u << stat; - } - if (bits) - { - enum Stat statId; - do - { - statId = (Random() % (NUM_BATTLE_STATS - 1)) + 1; - } while (!(bits & (1u << statId))); - - gBattleStruct->moveResultFlags[cv->battlerDef] = MOVE_RESULT_ATTEMPT_STAT_CHANGE; - SetStatChange(cv->battlerDef, statId, 2); - BattleScriptCall(BattleScript_PlayMoveAnim); - return MOVE_RESULT_RUN_SCRIPT_INCREMENT; - } - else - { - gBattlescriptCurrInstr = BattleScript_StatChangeFailed; - return MOVE_RESULT_FAILURE; - } - break; - } case EFFECT_STUFF_CHEEKS: // Back up current queue for later use memcpy( diff --git a/test/battle/move_effect/acupressure.c b/test/battle/move_effect/acupressure.c index 6eaade94ae..b0d7b61e19 100644 --- a/test/battle/move_effect/acupressure.c +++ b/test/battle/move_effect/acupressure.c @@ -1,13 +1,6 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Acupressure increases one of its stats by 2 stages at random"); -TO_DO_BATTLE_TEST("Acupressure doesn't try to increase a stat that has been maximized"); -TO_DO_BATTLE_TEST("Acupressure fails on the user if all of its stats are maximized"); -TO_DO_BATTLE_TEST("Acupressure fails on the ally if all of its stats are maximized"); -TO_DO_BATTLE_TEST("Acupressure works on the user if it's behind a Substitute (Gen5+)"); -TO_DO_BATTLE_TEST("Acupressure fails on its ally if it's behind a Substitute"); - DOUBLE_BATTLE_TEST("Acupressure fails on the user if it targeted its ally but switched positions via Ally Switch") { GIVEN { @@ -50,8 +43,112 @@ DOUBLE_BATTLE_TEST("Acupressure works on the ally if it targeted itself but swit } } -TO_DO_BATTLE_TEST("Acupressure works on the user if its side is protected by Crafty Shield"); -TO_DO_BATTLE_TEST("Acupressure fails on the ally if its side is protected by Crafty Shield"); +DOUBLE_BATTLE_TEST("Acupressure will not try to raise partners stat if it already increased its own") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentRight); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + } + } +} + +DOUBLE_BATTLE_TEST("Acupressure works on the user if its side is protected by Crafty Shield") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_CRAFTY_SHIELD) == EFFECT_PROTECT); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); + MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentRight); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CRAFTY_SHIELD, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + } +} + +DOUBLE_BATTLE_TEST("Acupressure works on the ally if its side is protected by Crafty Shield") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_CRAFTY_SHIELD) == EFFECT_PROTECT); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); + MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CRAFTY_SHIELD, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + } +} + +DOUBLE_BATTLE_TEST("Acupressure works on the user if it's behind a Substitute (Gen5+)") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponentRight, MOVE_SUBSTITUTE); } + TURN { MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentRight); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + } +} + +DOUBLE_BATTLE_TEST("Acupressure fails on its ally if it's behind a Substitute") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_SUBSTITUTE); + MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponentLeft); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + } + } +} + + +TO_DO_BATTLE_TEST("Acupressure fails on the user if all of its stats are maximized"); +TO_DO_BATTLE_TEST("Acupressure fails on the ally if all of its stats are maximized"); +TO_DO_BATTLE_TEST("Acupressure doesn't try to increase a stat that has been maximized"); +TO_DO_BATTLE_TEST("Acupressure increases one of its stats by 2 stages at random"); // Triple Battles required to test //TO_DO_BATTLE_TEST("Acupressure works on the ally if the user targeted itself but switched positions via Triple Battle shift before execution"); From 63e5951d947f5729211975c35573d5c96f78a518 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sun, 31 May 2026 09:51:28 +0200 Subject: [PATCH 09/59] Fixes Random Move from disobedience (#10093) --- src/battle_move_resolution.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/battle_move_resolution.c b/src/battle_move_resolution.c index 0dc806bfa0..d699996bc4 100644 --- a/src/battle_move_resolution.c +++ b/src/battle_move_resolution.c @@ -231,6 +231,7 @@ static enum CancelerResult CancelerObedience(struct BattleCalcValues *cv) return CANCELER_RESULT_FAILURE; case DISOBEYS_RANDOM_MOVE: gCurrentMove = gCalledMove = gBattleMons[cv->battlerAtk].moves[gCurrMovePos]; + gBattlescriptCurrInstr = GetMoveBattleScript(gCalledMove); BattleScriptCall(BattleScript_IgnoresAndUsesRandomMove); gBattlerTarget = GetBattleMoveTarget(gCalledMove, TARGET_NONE); return CANCELER_RESULT_RUN_SCRIPT_AND_INCREMENT; From e7c30866efa029019618f36a9ff2afbfc8345870 Mon Sep 17 00:00:00 2001 From: Viperio <146665252+Viperio19@users.noreply.github.com> Date: Sun, 31 May 2026 11:20:40 +0200 Subject: [PATCH 10/59] Fix colosseum warps frlg (#10100) --- data/scripts/cable_club_frlg.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/scripts/cable_club_frlg.inc b/data/scripts/cable_club_frlg.inc index bd2f91a412..bba62dda1d 100644 --- a/data/scripts/cable_club_frlg.inc +++ b/data/scripts/cable_club_frlg.inc @@ -298,7 +298,7 @@ CableClub_EventScript_EnterColosseum_Frlg:: release goto_if_eq VAR_0x8004, USING_MULTI_BATTLE, CableClub_EventScript_WarpTo4PColosseum_Frlg special SetCableClubWarp - warp MAP_BATTLE_COLOSSEUM_2P, 6, 8 + warp MAP_BATTLE_COLOSSEUM_2P_FRLG, 6, 8 special DoCableClubWarp end @@ -310,7 +310,7 @@ CableClub_EventScript_PlayerApproachLinkRoomRight_Frlg:: CableClub_EventScript_WarpTo4PColosseum_Frlg:: special SetCableClubWarp - warp MAP_BATTLE_COLOSSEUM_4P, 5, 8 + warp MAP_BATTLE_COLOSSEUM_4P_FRLG, 5, 8 special DoCableClubWarp end From d8f3349d6f13bdb3e37f0ba3ada2ead2fd8b00e3 Mon Sep 17 00:00:00 2001 From: Viperio <146665252+Viperio19@users.noreply.github.com> Date: Sun, 31 May 2026 14:03:34 +0200 Subject: [PATCH 11/59] Fix link singles and doubles using incorrect parties (#10102) --- src/battle_controllers.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 4349200cb4..89945ade8e 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -3297,7 +3297,7 @@ void FreeShinyStars(void) enum BattleTrainer GetBattlerTrainer(enum BattlerId battler) { - if (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI) + if (gBattleTypeFlags & BATTLE_TYPE_LINK) { switch (gBattlerBattleController[battler]) { @@ -3310,7 +3310,9 @@ enum BattleTrainer GetBattlerTrainer(enum BattlerId battler) case BATTLE_CONTROLLER_LINK_OPPONENT: case BATTLE_CONTROLLER_RECORDED_OPPONENT: case BATTLE_CONTROLLER_OPPONENT: - return (battler & BIT_FLANK) ? B_TRAINER_OPPONENT_B : B_TRAINER_OPPONENT_A; + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + return (battler & BIT_FLANK) ? B_TRAINER_OPPONENT_B : B_TRAINER_OPPONENT_A; + return B_TRAINER_OPPONENT_A; default: break; } From b1d93086231d83f0dbe0fd620df2bb6fe780e9fe Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Sun, 31 May 2026 20:30:49 +0200 Subject: [PATCH 12/59] Clean up sSpriteTileRanges (#2299) Co-authored-by: Hedara --- src/sprite.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/sprite.c b/src/sprite.c index 708a3e7fdf..82f8d3935e 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -10,8 +10,8 @@ #define SET_SPRITE_TILE_RANGE(index, start, count) \ { \ - sSpriteTileRanges[index * 2] = start; \ - (sSpriteTileRanges + 1)[index * 2] = count; \ + sSpriteTileRanges[index][0] = start; \ + sSpriteTileRanges[index][1] = count; \ } #define ALLOC_SPRITE_TILE(n) \ @@ -269,7 +269,7 @@ static const struct OamDimensions sOamDimensions[3][4] = // iwram bss static u16 sSpriteTileRangeTags[MAX_SPRITES]; -static u16 sSpriteTileRanges[MAX_SPRITES * 2]; +static u16 sSpriteTileRanges[MAX_SPRITES][2]; static struct AffineAnimState sAffineAnimStates[OAM_MATRIX_COUNT]; static u16 sSpritePaletteTags[16]; @@ -1512,14 +1512,10 @@ void FreeSpriteTilesByTag(u16 tag) if (index != 0xFF) { u16 i; - u16 *rangeStarts; - u16 *rangeCounts; u16 start; u16 count; - rangeStarts = sSpriteTileRanges; - start = rangeStarts[index * 2]; - rangeCounts = sSpriteTileRanges + 1; - count = rangeCounts[index * 2]; + start = sSpriteTileRanges[index][0]; + count = sSpriteTileRanges[index][1]; for (i = start; i < start + count; i++) FREE_SPRITE_TILE(i); @@ -1544,7 +1540,7 @@ u16 GetSpriteTileStartByTag(u16 tag) u8 index = IndexOfSpriteTileTag(tag); if (index == 0xFF) return 0xFFFF; - return sSpriteTileRanges[index * 2]; + return sSpriteTileRanges[index][0]; } u8 IndexOfSpriteTileTag(u16 tag) @@ -1564,7 +1560,7 @@ u16 GetSpriteTileTagByTileStart(u16 start) for (i = 0; i < MAX_SPRITES; i++) { - if (sSpriteTileRangeTags[i] != TAG_NONE && sSpriteTileRanges[i * 2] == start) + if (sSpriteTileRangeTags[i] != TAG_NONE && sSpriteTileRanges[i][0] == start) return sSpriteTileRangeTags[i]; } From 6683f5b992d541138df2e7e4fbdf6f78d4b76193 Mon Sep 17 00:00:00 2001 From: GGbond Date: Mon, 1 Jun 2026 07:35:11 +0800 Subject: [PATCH 13/59] Add missing item sort types (#10104) --- src/data/items.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/data/items.h b/src/data/items.h index e0e4de468e..8f3662ec97 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -14669,6 +14669,7 @@ const struct ItemInfo gItemsInfo[] = "prevented for this\n" "items's holder."), .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_HELD_ITEM, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, .flingPower = 30, @@ -15779,6 +15780,7 @@ const struct ItemInfo gItemsInfo[] = .price = 1200, .description = sQuestionMarksDesc, .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_AUX_ITEM, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, //.effect = currently missing @@ -15792,6 +15794,7 @@ const struct ItemInfo gItemsInfo[] = .price = 1200, .description = sQuestionMarksDesc, .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_AUX_ITEM, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, //.effect = currently missing @@ -15806,6 +15809,7 @@ const struct ItemInfo gItemsInfo[] = .price = 1600, .description = sQuestionMarksDesc, .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_AUX_ITEM, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, //.effect = currently missing From d332ba92c6b052049a35beba3badfa7053ba184c Mon Sep 17 00:00:00 2001 From: PCG <75729017+PCG06@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:07:31 +0530 Subject: [PATCH 14/59] =?UTF-8?q?Use=20values=20from=20`enum=20PokeBall`?= =?UTF-8?q?=20for=20Pok=C3=A9=20Balls=20(#10106)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/battle_anim.h | 4 ++-- include/pokeball.h | 4 ++-- src/battle_anim_throw.c | 14 +++++++------- src/battle_controller_player.c | 14 ++++++++------ src/battle_frontier.c | 2 +- src/battle_main.c | 2 +- src/battle_script_commands.c | 8 +++++--- src/pokeball.c | 17 ++++++++++------- src/pokemon.c | 4 ++-- 9 files changed, 38 insertions(+), 31 deletions(-) diff --git a/include/battle_anim.h b/include/battle_anim.h index b3cfc97d60..ead7730e6e 100644 --- a/include/battle_anim.h +++ b/include/battle_anim.h @@ -270,8 +270,8 @@ extern const union AffineAnimCmd *const gAffineAnims_SpinningBone[]; // battle_anim_throw.c void TryShinyAnimation(enum BattlerId battler, struct Pokemon *mon); -u8 AnimateBallOpenParticles(u8 x, u8 y, u8 priority, u8 subpriority, u8 ballId); -u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalettes, u8 ballId); +u8 AnimateBallOpenParticles(u8 x, u8 y, u8 priority, u8 subpriority, enum PokeBall ballId); +u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalettes, enum PokeBall ballId); bool32 IsCriticalCapture(void); // battle_anim_utility_funcs.c void InitStatsChangeAnimation(u8 taskId); diff --git a/include/pokeball.h b/include/pokeball.h index 036cff9275..09a3184b25 100644 --- a/include/pokeball.h +++ b/include/pokeball.h @@ -30,8 +30,8 @@ void CreatePokeballSpriteToReleaseMon(u8 monSpriteId, u8 monPalNum, u8 x, u8 y, u8 CreateTradePokeballSprite(u8 monSpriteId, u8 monPalNum, u8 x, u8 y, u8 oamPriority, u8 subPriority, u8 delay, u32 fadePalettes); void StartHealthboxSlideIn(enum BattlerId battler); void DoHitAnimHealthboxEffect(enum BattlerId battler); -void LoadBallGfx(u8 ballId); -void FreeBallGfx(u8 ballId); +void LoadBallGfx(enum PokeBall ballId); +void FreeBallGfx(enum PokeBall ballId); enum PokeBall ItemIdToBallId(u32 ballItem); #endif // GUARD_POKEBALL_H diff --git a/src/battle_anim_throw.c b/src/battle_anim_throw.c index dd4cc2fbdf..1b065c3eba 100644 --- a/src/battle_anim_throw.c +++ b/src/battle_anim_throw.c @@ -71,7 +71,7 @@ static void SpriteCB_Ball_Capture_Step(struct Sprite *); static void MakeCaptureStars(struct Sprite *); static void SpriteCB_Ball_FadeOut(struct Sprite *); static void DestroySpriteAfterOneFrame(struct Sprite *); -static void LoadBallParticleGfx(u8); +static void LoadBallParticleGfx(enum PokeBall); static void SpriteCB_CaptureStar_Flicker(struct Sprite *); static void SpriteCB_Ball_Release_Wait(struct Sprite *); static void SpriteCB_Ball_Block_Step(struct Sprite *); @@ -1600,7 +1600,7 @@ static void SpriteCB_Ball_Block_Step(struct Sprite *sprite) #undef sFrame -static void LoadBallParticleGfx(u8 ballId) +static void LoadBallParticleGfx(enum PokeBall ballId) { if (GetSpriteTileStartByTag(sBallParticles[ballId].pic.tag) == 0xFFFF) { @@ -1609,7 +1609,7 @@ static void LoadBallParticleGfx(u8 ballId) } } -u8 AnimateBallOpenParticles(u8 x, u8 y, u8 priority, u8 subpriority, u8 ballId) +u8 AnimateBallOpenParticles(u8 x, u8 y, u8 priority, u8 subpriority, enum PokeBall ballId) { u8 taskId; @@ -1636,7 +1636,7 @@ static void PokeBallOpenParticleAnimation(u8 taskId) u8 spriteId; u8 x, y; u8 priority, subpriority; - u8 ballId; + enum PokeBall ballId; u8 var0; ballId = gTasks[taskId].data[15]; @@ -2065,7 +2065,7 @@ static void DestroyBallOpenAnimationParticle(struct Sprite *sprite) #define tPaletteHi data[11] #define tBallId data[15] -u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalettes, u8 ballId) +u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalettes, enum PokeBall ballId) { u8 taskId; @@ -2094,7 +2094,7 @@ u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalette static void Task_FadeMon_ToBallColor(u8 taskId) { - u8 ballId = gTasks[taskId].tBallId; + enum PokeBall ballId = gTasks[taskId].tBallId; if (gTasks[taskId].tTimer <= 16) { @@ -2122,7 +2122,7 @@ static void Task_FadeMon_ToNormal(u8 taskId) static void Task_FadeMon_ToNormal_Step(u8 taskId) { - u8 ballId = gTasks[taskId].tBallId; + enum PokeBall ballId = gTasks[taskId].tBallId; if (gTasks[taskId].tTimer <= 16) { diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 4b9c50600f..246dff4233 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -195,12 +195,13 @@ static void CompleteOnBattlerSpritePosX_0(enum BattlerId battler) BtlController_Complete(battler); } -static u16 GetPrevBall(u16 ballId) +static enum Item GetPrevBall(enum Item ballId) { s32 i; - s32 index = ItemIdToBallId(ballId); - u32 newBall = 0; - for (i = 0; i < POKEBALL_COUNT; i++) + enum PokeBall index = ItemIdToBallId(ballId); + enum Item newBall = ITEM_NONE; + + for (i = 0; i < POKEBALL_COUNT; i++) { index--; if (index == -1) @@ -212,11 +213,12 @@ static u16 GetPrevBall(u16 ballId) return ballId; } -static u32 GetNextBall(u32 ballId) +static enum Item GetNextBall(enum Item ballId) { s32 i; s32 index = ItemIdToBallId(ballId); - u32 newBall = 0; + enum Item newBall = ITEM_NONE; + for (i = 0; i < POKEBALL_COUNT; i++) { index++; diff --git a/src/battle_frontier.c b/src/battle_frontier.c index fcbc8c043b..df33e17200 100644 --- a/src/battle_frontier.c +++ b/src/battle_frontier.c @@ -308,7 +308,7 @@ static void FillTrainerParty(u16 trainerId, enum BattleTrainer trainer, u8 monCo void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 otID, u32 flags, struct Pokemon *dst) { - u8 ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball; + enum PokeBall ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball; enum Move move; u32 personality = 0, ability, friendship, j; diff --git a/src/battle_main.c b/src/battle_main.c index 62cfd328de..3d5341a824 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -1987,7 +1987,7 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer if (B_TRAINER_CLASS_POKE_BALLS >= GEN_7 && ball == -1) { - ball = gTrainerClasses[trainer->trainerClass].ball ?: ITEM_POKE_BALL; + ball = gTrainerClasses[trainer->trainerClass].ball ?: BALL_POKE; SetMonData(&party[i], MON_DATA_POKEBALL, &ball); } } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 0e2173ecc0..b4b9b832f1 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -9690,7 +9690,7 @@ u8 GetCatchingBattler(void) static void FinalizeCapture(void) { - u32 ballId = ItemIdToBallId(gLastThrownBall); + enum PokeBall ballId = ItemIdToBallId(gLastThrownBall); enum NationalDexOrder natDexNo = SpeciesToNationalPokedexNum(gBattleMons[gBattlerTarget].species); if ((GetConfig(B_CRITICAL_CAPTURE_IF_OWNED) >= GEN_9 && GetSetPokedexFlag(natDexNo, FLAG_GET_CAUGHT)) || IsCriticalCapture()) @@ -9737,7 +9737,7 @@ struct BallData static void ComputeBallData(u32 wildMonBattler, u32 playerBattler, struct BallData *ball) { u32 i; - u32 ballId = ItemIdToBallId(gLastUsedItem); + enum PokeBall ballId = ItemIdToBallId(gLastUsedItem); struct BattlePokemon *battleMon = &gBattleMons[wildMonBattler]; ball->multiplier = 100; @@ -9919,6 +9919,8 @@ static void ComputeBallData(u32 wildMonBattler, u32 playerBattler, struct BallDa ball->multiplier = 410; ball->divider = 4096; break; + default: + break; } } @@ -10072,7 +10074,7 @@ static void Cmd_handleballthrow(void) if (gTestRunnerEnabled) TestRunner_Battle_RecordCatchChance(odds); - u32 ballId = ItemIdToBallId(gLastUsedItem); + enum PokeBall ballId = ItemIdToBallId(gLastUsedItem); if (gBattleResults.catchAttempts[ballId] < 255) gBattleResults.catchAttempts[ballId]++; diff --git a/src/pokeball.c b/src/pokeball.c index c8d9f5e4a7..1bca450a35 100644 --- a/src/pokeball.c +++ b/src/pokeball.c @@ -45,7 +45,7 @@ static void SpriteCB_TradePokeballEnd(struct Sprite *sprite); static void SpriteCB_HealthboxSlideInDelayed(struct Sprite *sprite); static void SpriteCB_HealthboxSlideIn(struct Sprite *sprite); static void SpriteCB_HitAnimHealthoxEffect(struct Sprite *sprite); -static u16 GetBattlerPokeballItemId(enum BattlerId battler); +static enum PokeBall GetBattlerPokeballItemId(enum BattlerId battler); // rom const data @@ -400,7 +400,8 @@ u8 DoPokeballSendOutAnimation(enum BattlerId battler, s16 pan, u8 kindOfThrow) static void Task_DoPokeballSendOutAnim(u8 taskId) { - u32 throwCaseId, ballId, ballSpriteId; + u32 throwCaseId, ballSpriteId; + enum PokeBall ballId; enum BattlerId battler; bool32 notSendOut = FALSE; u32 throwXoffset = (B_ENEMY_THROW_BALLS >= GEN_6 && !gTestRunnerHeadless) ? 24 : 0; @@ -491,7 +492,7 @@ static void SpriteCB_BallThrow(struct Sprite *sprite) { if (TranslateAnimHorizontalArc(sprite)) { - u16 ballId; + enum PokeBall ballId; u8 taskId = sprite->oam.affineParam; u8 opponentBattler = gTasks[taskId].tOpponentBattler; u8 noOfShakes = gTasks[taskId].tThrowId; @@ -816,7 +817,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId) static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite) { enum BattlerId battler = sprite->sBattler; - u32 ballId; + enum PokeBall ballId; StartSpriteAnim(sprite, 1); ballId = GetBattlerPokeballItemId(battler); @@ -1395,7 +1396,7 @@ static void SpriteCB_HitAnimHealthoxEffect(struct Sprite *sprite) } } -void LoadBallGfx(u8 ballId) +void LoadBallGfx(enum PokeBall ballId) { u16 var; @@ -1414,16 +1415,18 @@ void LoadBallGfx(u8 ballId) var = GetSpriteTileStartByTag(gPokeBalls[ballId].pic.tag); DecompressDataWithHeaderVram(gOpenPokeballGfx, (void *)(OBJ_VRAM0 + 0x100 + var * 32)); break; + default: + break; } } -void FreeBallGfx(u8 ballId) +void FreeBallGfx(enum PokeBall ballId) { FreeSpriteTilesByTag(gPokeBalls[ballId].pic.tag); FreeSpritePaletteByTag(gPokeBalls[ballId].palette.tag); } -static u16 GetBattlerPokeballItemId(enum BattlerId battler) +static enum PokeBall GetBattlerPokeballItemId(enum BattlerId battler) { struct Pokemon *illusionMon; struct Pokemon *mon = GetBattlerMon(battler); diff --git a/src/pokemon.c b/src/pokemon.c index a697832a43..916ed552d7 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -1006,7 +1006,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, enum Species species, u8 level, u32 SetBoxMonData(boxMon, MON_DATA_MET_LOCATION, &value); SetBoxMonData(boxMon, MON_DATA_MET_LEVEL, &level); SetBoxMonData(boxMon, MON_DATA_MET_GAME, &gGameVersion); - value = ITEM_POKE_BALL; + value = BALL_POKE; SetBoxMonData(boxMon, MON_DATA_POKEBALL, &value); SetBoxMonData(boxMon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender); @@ -5038,7 +5038,7 @@ s32 CalculateFriendshipBonuses(struct Pokemon *mon, s32 modifier, enum HoldEffec if (modifier == 0) return bonus; - if (GetMonData(mon, MON_DATA_POKEBALL) == ITEM_LUXURY_BALL) + if (GetMonData(mon, MON_DATA_POKEBALL) == BALL_LUXURY) bonus += ITEM_FRIENDSHIP_LUXURY_BONUS; if (GetMonData(mon, MON_DATA_MET_LOCATION) == GetCurrentRegionMapSectionId()) From a7cfa0ddd5f853bbe368a370998cd67b7a5084a5 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Mon, 1 Jun 2026 19:42:09 +0100 Subject: [PATCH 15/59] Cleanup 'message 0x0' (#10110) --- data/scripts/std_msgbox.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/scripts/std_msgbox.inc b/data/scripts/std_msgbox.inc index 541ec384d1..cb95b5ebf7 100644 --- a/data/scripts/std_msgbox.inc +++ b/data/scripts/std_msgbox.inc @@ -33,7 +33,7 @@ Std_ReceivedItem:: textcolor NPC_TEXT_COLOR_NEUTRAL call_if_eq VAR_0x8002, MUS_LEVEL_UP, EventScript_ReceivedItemFanfare1 call_if_eq VAR_0x8002, MUS_RG_OBTAIN_KEY_ITEM, EventScript_ReceivedItemFanfare2 - message 0x0 + message NULL waitmessage waitfanfare call_if_eq VAR_0x8002, MUS_LEVEL_UP, EventScript_ReceivedItemWaitFanfare From 18e2f17fc1d1ea356c7a0751d8e8625bd179a17c Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Mon, 1 Jun 2026 19:51:12 +0100 Subject: [PATCH 16/59] SanitizeBagItemId, TryTakeMonItemResult (#10109) --- src/item.c | 25 +++++++++++++++++++++++-- src/party_menu.c | 24 ++++++++++++++++-------- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/item.c b/src/item.c index cec77d7dfb..e060343c30 100644 --- a/src/item.c +++ b/src/item.c @@ -34,6 +34,8 @@ static bool32 CheckPyramidBagHasSpace(enum Item itemId, u16 count); static const u8 *GetItemPluralName(enum Item); static bool32 DoesItemHavePluralName(enum Item); static void NONNULL BagPocket_CompactItems(struct BagPocket *pocket); +static u16 SanitizeItemId(enum Item itemId); +static u16 SanitizeBagItemId(enum Item itemId); EWRAM_DATA struct BagPocket gBagPockets[POCKETS_COUNT] = {0}; @@ -347,7 +349,8 @@ static bool32 NONNULL BagPocket_AddItem(struct BagPocket *pocket, enum Item item bool32 AddBagItem(enum Item itemId, u16 count) { - if (GetItemPocket(itemId) >= POCKETS_COUNT) + itemId = SanitizeBagItemId(itemId); + if (itemId == ITEM_NONE) return FALSE; // check Battle Pyramid Bag @@ -403,7 +406,8 @@ static bool32 NONNULL BagPocket_RemoveItem(struct BagPocket *pocket, enum Item i bool32 RemoveBagItem(enum Item itemId, u16 count) { - if (GetItemPocket(itemId) >= POCKETS_COUNT || itemId == ITEM_NONE) + itemId = SanitizeBagItemId(itemId); + if (itemId == ITEM_NONE) return FALSE; // check Battle Pyramid Bag @@ -789,6 +793,23 @@ static u16 SanitizeItemId(enum Item itemId) return itemId; } +static u16 SanitizeBagItemId(enum Item itemId) +{ + itemId = SanitizeItemId(itemId); + + assertf(itemId != ITEM_NONE, "invalid bag item: ITEM_NONE") + { + return ITEM_NONE; + } + + assertf(GetItemPocket(itemId) < POCKETS_COUNT, "invalid bag item pocket: %S", gItemsInfo[itemId].name) + { + return ITEM_NONE; + } + + return itemId; +} + const u8 *GetItemName(enum Item itemId) { const u8 *name = gItemsInfo[SanitizeItemId(itemId)].name; diff --git a/src/party_menu.c b/src/party_menu.c index 6f1bb96e9e..486cca885c 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -2119,19 +2119,27 @@ static void GiveItemToMon(struct Pokemon *mon, enum Item item) TryItemHoldFormChange(&gParties[B_TRAINER_PLAYER][gPartyMenu.slotId], gPartyMenu.slotId, B_TRAINER_PLAYER); } -static u8 TryTakeMonItem(struct Pokemon *mon) +enum TryTakeMonItemResult +{ + TAKE_NO_ITEM, + TAKE_NO_BAG_SPACE, + TAKE_OK, +}; + +static enum TryTakeMonItemResult TryTakeMonItem(struct Pokemon *mon) { enum Item item = GetMonData(mon, MON_DATA_HELD_ITEM); if (item == ITEM_NONE) - return 0; - if (AddBagItem(item, 1) == FALSE) - return 1; + return TAKE_NO_ITEM; + + if (!AddBagItem(item, 1)) + return TAKE_NO_BAG_SPACE; item = ITEM_NONE; SetMonData(mon, MON_DATA_HELD_ITEM, &item); TryItemHoldFormChange(&gParties[B_TRAINER_PLAYER][gPartyMenu.slotId], gPartyMenu.slotId, B_TRAINER_PLAYER); - return 2; + return TAKE_OK; } static void BufferBagFullCantTakeItemMessage(u16 itemUnused) @@ -3652,16 +3660,16 @@ static void CursorCb_TakeItem(u8 taskId) PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]); switch (TryTakeMonItem(mon)) { - case 0: // Not holding item + case TAKE_NO_ITEM: GetMonNickname(mon, gStringVar1); StringExpandPlaceholders(gStringVar4, gText_PkmnNotHolding); DisplayPartyMenuMessage(gStringVar4, TRUE); break; - case 1: // No room to take item + case TAKE_NO_BAG_SPACE: BufferBagFullCantTakeItemMessage(item); DisplayPartyMenuMessage(gStringVar4, TRUE); break; - default: // Took item + case TAKE_OK: DisplayTookHeldItemMessage(mon, item, TRUE); break; } From 184b72ec69284e64bdbfa0996c8f4c7a2ee8cc5e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:16:34 +0100 Subject: [PATCH 17/59] add Gastly92 as a contributor for code (#10114) Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ CREDITS.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index a441c1abc7..8bf6a50314 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -715,6 +715,15 @@ "contributions": [ "code" ] + }, + { + "login": "Gastly92", + "name": "Gastly92", + "avatar_url": "https://avatars.githubusercontent.com/u/262681076?v=4", + "profile": "https://github.com/Gastly92", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/CREDITS.md b/CREDITS.md index ac6209db3b..562908a905 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -83,7 +83,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Gamer2020
Gamer2020

💻 SonikkuA-DatH
SonikkuA-DatH

🎨 Jaizu
Jaizu

💻 - Miriam
Miriam

💻 + Kildemal
Kildemal

💻 Skeli
Skeli

🎨 Josh Hufford
Josh Hufford

💻 Kasenn
Kasenn

💻 @@ -102,6 +102,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d blusunrize
blusunrize

🐛 💻 jtebbe
jtebbe

💻 Liam
Liam

💻 + Gastly92
Gastly92

💻 From 95c2493756c5d75eeb95bdbd7eea48fb4b7c898c Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Tue, 2 Jun 2026 00:03:03 +0200 Subject: [PATCH 18/59] Fix missing incgfx for Mega Garchomp Z (#10116) Co-authored-by: Hedara --- src/data/graphics/pokemon.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/graphics/pokemon.h b/src/data/graphics/pokemon.h index 503ca34556..70b60eaa93 100644 --- a/src/data/graphics/pokemon.h +++ b/src/data/graphics/pokemon.h @@ -15314,9 +15314,9 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_MEGA_EVOLUTIONS #if P_GEN_9_MEGA_EVOLUTIONS - const u32 gMonFrontPic_GarchompMegaZ[] = INCBIN_U32("graphics/pokemon/garchomp/mega_z/front.4bpp.smol"); + const u32 gMonFrontPic_GarchompMegaZ[] = INCGFX_U32("graphics/pokemon/garchomp/mega_z/front.png", ".4bpp.smol"); const u16 gMonPalette_GarchompMegaZ[] = INCGFX_U16("graphics/pokemon/garchomp/mega_z/normal.pal", ".gbapal"); - const u32 gMonBackPic_GarchompMegaZ[] = INCBIN_U32("graphics/pokemon/garchomp/mega_z/back.4bpp.smol"); + const u32 gMonBackPic_GarchompMegaZ[] = INCGFX_U32("graphics/pokemon/garchomp/mega_z/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_GarchompMegaZ[] = INCGFX_U16("graphics/pokemon/garchomp/mega_z/shiny.pal", ".gbapal"); const u8 gMonIcon_GarchompMegaZ[] = INCGFX_U8("graphics/pokemon/garchomp/mega_z/icon.png", ".4bpp"); #if OW_POKEMON_OBJECT_EVENTS && OW_BATTLE_ONLY_FORMS From 1b920b67b6900f80403afac92e3421054b73caf9 Mon Sep 17 00:00:00 2001 From: Ruby Date: Tue, 2 Jun 2026 18:38:33 +0800 Subject: [PATCH 19/59] Fix Trainer Party Pool documentation (#10122) --- docs/tutorials/how_to_trainer_party_pool.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/how_to_trainer_party_pool.md b/docs/tutorials/how_to_trainer_party_pool.md index e111ba957e..b0045249c8 100644 --- a/docs/tutorials/how_to_trainer_party_pool.md +++ b/docs/tutorials/how_to_trainer_party_pool.md @@ -3,7 +3,7 @@ Trainer Party Pools (TPP) is a way to introduce a bit of unpredictability to tra The maximum number of mons that can be in a single trainer's pool is 255. -## Turning on TPP with `trainer.sparty` +## Turning on TPP with `trainers.party` To use TPP with `trainers.party`, all that's needed is to define a `Party Size` that's smaller than than the number of defined mons for the trainer. ## Turning on TPP with `trainers.h` @@ -69,7 +69,7 @@ Double Battle: Yes AI: Check Bad Move Party Size: 4 Pool Rules: Weather Doubles -Pool Pick Index: Default +Pool Pick Functions: Default Zigzagoon Level: 4 From 9953e12ffc6fd2fe487218e58c87b05ce4763ee5 Mon Sep 17 00:00:00 2001 From: Danny Wang <74725787+ThePeeps191@users.noreply.github.com> Date: Tue, 2 Jun 2026 05:38:18 -0600 Subject: [PATCH 20/59] Fix broken/old links in CREDITS.md (#10120) --- CREDITS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 562908a905..3f04113093 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,6 +1,6 @@ ## Credits ✨ -Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/en/reference/emoji-key/)): @@ -120,7 +120,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! +This project follows the [all-contributors](https://github.com/all-contributors/allcontributors.org) specification. Contributions of any kind welcome! ## Other Credits ### Mega Evolution Overworld Sprite Credits: From 35c3807e74c46b4a43c6c114113d27ac6315f933 Mon Sep 17 00:00:00 2001 From: Miriam Date: Tue, 2 Jun 2026 18:38:54 +0530 Subject: [PATCH 21/59] chore(credits): change kildemal to miriam in credits (#10123) --- .all-contributorsrc | 6 +++--- CREDITS.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 8bf6a50314..b80a18d4c5 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -581,10 +581,10 @@ ] }, { - "login": "izrofid", - "name": "Kildemal", + "login": "miriamlefae", + "name": "Miriam", "avatar_url": "https://avatars.githubusercontent.com/u/206095739?v=4", - "profile": "https://github.com/izrofid", + "profile": "https://github.com/miriamlefae", "contributions": [ "code" ] diff --git a/CREDITS.md b/CREDITS.md index 3f04113093..f761d3f086 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -83,7 +83,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/e Gamer2020
Gamer2020

💻 SonikkuA-DatH
SonikkuA-DatH

🎨 Jaizu
Jaizu

💻 - Kildemal
Kildemal

💻 + Miriam
Miriam

💻 Skeli
Skeli

🎨 Josh Hufford
Josh Hufford

💻 Kasenn
Kasenn

💻 From 77511ae815441697a09ff3e462c448c64c014c65 Mon Sep 17 00:00:00 2001 From: mudskip <105766191+mudskipper13@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:06:40 +0700 Subject: [PATCH 22/59] feat (battle): improve gimmick triggers' graphics (#10129) --- graphics/battle_interface/burst_trigger.png | Bin 6979 -> 345 bytes graphics/battle_interface/dynamax_trigger.png | Bin 6864 -> 338 bytes graphics/battle_interface/mega_trigger.pal | 19 ------------------ graphics/battle_interface/mega_trigger.png | Bin 3454 -> 329 bytes graphics/battle_interface/tera_trigger.png | Bin 7449 -> 324 bytes graphics/battle_interface/z_move_trigger.png | Bin 7470 -> 358 bytes src/battle_gimmick.c | 4 ++-- src/data/graphics/gimmicks.h | 2 +- 8 files changed, 3 insertions(+), 22 deletions(-) delete mode 100644 graphics/battle_interface/mega_trigger.pal diff --git a/graphics/battle_interface/burst_trigger.png b/graphics/battle_interface/burst_trigger.png index bbd16ac5553f0ffa2cad56e4ad4ead08578252e5..f9b1f1370759ed47f7146c4697d00009ac71fec1 100644 GIT binary patch delta 330 zcmV-Q0k!_aHrWD@7=H)@0000?P=%ZT001yhOjJd=&!hPG_|)j(wYbB4pQdtbgnO5V zO=)2O0000000000`1ok(!&K3hJfwtXdSOc@d#Aww0087kL_t(YiS3lp4#OY_0CgZd z2>SnjyMQj)TE*8b8LxLm(>9mV=P;*mCZegFiA(0>qowj8IiuGRx&M68ockcBKFFaDRV40%2~i)av}r8)6oNif7i8ZD zF`>z}54DQ4xkF;XIZJD;_pZ9@gFSD2+XuTq*RK0MhzT0>VF*zlObGiRq8j%>^w0;< ce;=XpN&=f3aHb3e~@?l5yxLqR@qJ_rON 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 Ks+X(l5cD5`Jbp6( diff --git a/graphics/battle_interface/dynamax_trigger.png b/graphics/battle_interface/dynamax_trigger.png index 18f3a84cff77a8022df1117fb25f71bc37d9a713..954de81e7c631d0db7b7000de8bf70208902e1c8 100644 GIT binary patch delta 323 zcmca$dWmU*L_G&H0|SFkK(4xlV-{X&tCM$$p z>J$6iM0Rp*`oAjvKELCqP51ndMh5(;5ufucV2{rK)#5upIK6DHys~iS<(j{1Zu%A_ zKmPt>9zWOR+cgY6yvwp2=JT_yDV@y!%45g3p9xW1;akn*9~H9Ozopr05g-2SpWb4 literal 6864 zcmeHKc{r47*dKd#iIh0TAWLR743jN8$1n^f3A4PTVTQ?!>_?V5rH}~OvQ|`DXtQLG zLMo!NmAw+76jI+yopb8?&Ohh6zVE;0y54u5_kQmCci;E#x$ozCo})wuYjF{I5eNh# zZfj%V4E{sG$CRHBd>_r*mji)_*oC>cah=J*Pze6l{wnA}*DyZpjV z4{du-*Qae;k6YwO-qU5@iLPfM#+_{@>7Q0!RUf@9noEkFVMnEX?*EFP85F$bl~DMe zoQKI3U70_$)c&F^JvvuSU~lqooj!R>Vltm=UgYvT7jGMPAEmB~9GF>*FX}fbRJt1B zxqz%aG}X~$SidamaV26&YKAxFOXvo9q0^3XO+#I9i$VCiFhLdN+P0LHD_Zlir{=`9 z0<67Eg%@*i*`Ko8KQFBG%_AZWzKZR0h&O3hxZBr$=D{*+xtHx372Zi%@WfSa)Y0s4 zBwi*ySdYWlh)rB=-}C8rg|^ULgUxk=JfmF_^eKg16VX7`YW)(T zcndun>DO^DLJ(@%p5u006zW|rdJphv4&R?>xbYoB%tb?fD7vnARQUTTapo>#eicb3a8jNO;9_+pr@09{|I!Rlv z>0Eq@NU>Fu(`-(4cmJRZO)MGLy58-+hx+(#Yr?rLxQd=gNuz~sPP%8DM!tAX^r!Qti|r%4B<(?5Dy zchnH)g*0oN28kn1$-PnzW2%~T=y)ODekXot#jbYdesoyjLrwaPuu_=QC_+=eOOpcK zls?a>!c7e(FUMsaovm%?s6C-0GGG#&?KF93$MmlLKVqME`|B`KLdtM+LaBJ_kkzM1 z#+@X>ADzmw%Uw4YXYY;$yOSzgFKR<*_p`Hvg``if*|7ew8rysxpLUTe{8Rcde8CosHM0 z$69#VirG8GO0_%sF4hv-IDjiUAEsn-(tOqN6*@Z=X`zO6)77J-cvn zo-23_FU-E8P^(A_iP=vMR#(sH=@sja6V$If}~Y!j(Ecn`XeynXbX*xbDwrg=+Wf;@0Kl^#pw97?$$y}N5Sa-e*@eCPG$Oxr!4oD=K5@+v)^(W4Pax^K6SMih7}p4#%eUDf;b z6(54Fj>`P8$>&yDaj?~IPTnP*#e?jQd?i;C9Xn+nS4!*B$J>CEwpu#e&sG9$piteY z^Ew*u@ivodE)7Ul5;#SZzKQ*rel3j#^Xf%?%39`k)NLH|??DsFT~f&Bpz)P9cCK-8 z($>n7e1l?1+LKzOOKMIIrP?D8p?&EUE;jU34{q`{D-9XZ**ll+GyC#Ui>V*Ac!s;hMYaULht=X%QbPOEZP0b(iat7BK!*pnuR8ywg4MMj{cJ}yBR1^_ayRpk;`*skmRB|7+l z)a=y!CAOyfp^1>kP|a$xbs&fM(z+_mpOtv+^iU8~@e*k+^U1lEroGqqAS~Z@ue*mV z?YzEd$F6@rF2#*AHkUdQB)#E{grer16~C$K)FSDJ#|i?^E}6LZE+~#H1X+e~oBRxi z1va}@ryh?NoaL*8w_mw_exwo>cz9;lu*Aomy6ZycSb66&o^070{3-1+<_p-4Rg#~T z#Nv`;_-vE6>(ifVxW7maYl-FMSR3c7H{}3O6-UN!-oAXrqo#KQFL9->Mmr(=C(5mR)BbVo;v! zK(!~`EA@GC={xFkN4=(m3+CuV2f5IX8V%zmJ_C(qvJ}gR)@0YqODxTD=eGvq!31^R zJ)93&_^)n*N0|9Xr`#r3IYR@!Z{0^ zv^b>cgE;HovdR}U{lpRZE4O`O^XT2M^R*g&X@VFL#Jh#h6|c-rGUgMkqC?5jHzHUb zk9^8|9&1zVqQuxFwbL8tFHj}b(6CDfPdtxTcvOa+n2a=TG#|@KD_g%gbX46w=r?ng zbkVTa#%h5mF@|gJ0}&CReCuJ#*3R*L(z3>a4dN*hUMxn1$*J%l3nOWh2P@7Nd&p|r zpK=CvN)5}5Ik^?2@7U@+mq4xM=C$NI?_^k(5c&U*7Vs@;F#P=9RY~Tp0sp?@+gidw zJuK5Klzg}Xuezde-`JH`OR|CN7-cWQh+xCiomYs_;7z|Xui$h0Kh!{oBWWM*5Tg@XxcBwUb!Z$VY{!Yo&GKAtlOkCDQsZ+E{&Kwf(>z|L<&(0juimM~wY;Cr+rrM8c;uqx zk)q}9H{f889}G>lXdiFC^gOO6KQ7&tX3x2iSW+ON!NIu(Ns3L5KBKKnCLhl%!X-5w zsFrZ%wVU#7(dAY7BD;50cdiJpgob^Jt5BC3IG$ z7f2t{ms8vrLVwy?G=8+PiE=e|OoFavu9mwsQKQsq(X0nJG{4d3x-<1s_?+C~x#xD7 zZ?M)m@1L(TOWm0uvqAHDQs}2Y6{AjiU~b>{9(6O7)lzMd{329ar7KEG z@psk`&vVb@|cF0 zJ66(c5=YNz%81l0Z;m8MY^oLr>+K(OU)GO=V7i~oiL=@3j>~F>4~z^L<vbmnuM^)R6l?Vr2sw*e{4+5|NE*ToaV)}FNAx5w@ zTs$~l6(eELH5IO(5zLK1gqjBg0#Gahi$K9GLl_4zFk=y@VIYl;ceb$l4gr1{!S->v zY&;Sf92|@Y)})}Y$O_iLb6!MA1yds%L5?D_kjM@g5v_- z&XCRkCm<-03RoTh{JAPWLeQvx+p~iLnQQ6Ls7Qbbus~G~=oS5wOKV#K@o$S&3VawW z_L>z)_D`Bz2K^theu`~%W-Xl`0|Cwd#{EhAuiV#^K`jCSZxKKZS`E+E!U(qNA5ROQ zGHCd{JjsXUsQh$K5_2+QO{#0NU3IsA#sr4sCcV@Ko%KXP6mtY10dP{K5G-J zgyVM*ZH-_U1nM6NkxAy#K?AS{82+??V9q~NE({hx;*wYSMCSA>Caac4)7p?Py z{Z1f|1J>dyDjJ2rVAsr77X}Ze15!&~tyBcuY&9t8s^waN zLk+(ziw%PVYJ{%V{P(IS0sFsweQN?HV{HlwT`OEXnflEMhkO8_tvLeizD-g0k^OxD zu*1KX)L(MOzbqG>ib4V4+QKP1dIoSTmWG2HVCYylO@{{P=%Dn_6bj~NbWQ-B8%z!a zcKCpqg4uv2w3ZE2<2#v}KkEnY16G+rf&GorgQIaS7!)3h#p_^U$nVJ_S9|)eYz>kB zix0y!g&#Hn(C(WI++4uD3iZuB`6p8n?% z61B1O-q){R*X~LG{?b;7O#x?w**3d55Qyl8)rSX?nY{@V3UO@-mO|r#(tO&m^u&u9 zpy-yZ#SRz!wzntI5)CLZOVSwcrm88InuDhnAi{?f<11D6O-J$fi@c7D7P$MR!!hjx z+=%)`whj7BBV&T!tuB{Tw|#mxjaQ*1TGovX7;YC3JD$9sXXC-WOxe~IOy#Zq69Sv2 zU);rI*x8CQz3LvQJp!8T(O0LchN+(ORZ889?UEwt&(GnrGrzpE*&$`}x=FG$an?Qb zL#*$tO2~)Uh2fT-3rg7Km$l1}#{M9lzeYKG;`Ie3Qf|;4<;VRqFuPS2Y%Luu%FMiD F{s&w^Bc=cV diff --git a/graphics/battle_interface/mega_trigger.pal b/graphics/battle_interface/mega_trigger.pal deleted file mode 100644 index 2672d1f10a..0000000000 --- a/graphics/battle_interface/mega_trigger.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -185 207 163 -77 105 97 -199 159 199 -221 177 207 -57 151 117 -139 221 253 -247 161 133 -255 255 255 -153 87 67 -233 233 125 -129 255 223 -149 147 247 -195 207 201 -123 151 135 -0 0 0 -0 0 0 diff --git a/graphics/battle_interface/mega_trigger.png b/graphics/battle_interface/mega_trigger.png index a269ee738cd1905d9caba94efc346bf6a44e7be2..bdb3e8e95703ae17b229d5b2fcbed3750628009d 100644 GIT binary patch delta 314 zcmV-A0mc6Q8p#5X7=H)@0000?P=%ZT001yhOjJd=&!g1n;kCHKdzXhzX<+~W00000 z!fU$SvCoy0_lw>AO{<-O|KI89efOb-nO8%z6d{=a007iUL_t(YiS3k24udcZ1$p+9 z2u=d`zikzQs`9Z>*Wm38;6!MK;m=X>hD#`r05y0Vps@iPBf@ZIScED719-)u4`Ki5K?6Q)D`D?4khLAhA-dNz+s0Uz8U*d>^OxG?51acwj5j}2N?{*T;u!TIB{Btlm^e+GfqB8FN@l+gm0D}9K_6Bl>chf$3Hvb5Zy%mKALNk-?z5p*djJ3c M07*qoM6N<$g1;t?k^lez literal 3454 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 diff --git a/graphics/battle_interface/tera_trigger.png b/graphics/battle_interface/tera_trigger.png index 5498ea8806cfa40dc664e5f0c8b311e84c349ce2..660880acf92bae4ae4741430ae84a088d191e5f4 100644 GIT binary patch delta 309 zcmbPfb%bexL_G&H0|SFkKFvImi9i`-u>0!U zNeAB+FMbo#v(r6(`NQe+Ie^mVJzX3_JUZWooaQ^Mz@x2b`Sjrb|8HFuMw_cHw9Z>~ z)yrd>fyLVGZ@mSc+At;TbJV;k<`HY~pngU<0|N^a3xiD4zLFk}thF2LMfb>dcrE`O zEyMk0A8VFo^M8>yHA)qq8jn7B?EFa3vA}nU_?`vlYQ(wy(bwh(W7FVlwL1F^+te=2D!RhI=2(vP`|r*=7C%lT xefX%Ss4gG(`Op7q$GzX3WuQjh|NG%`1w+vSuFrd@`XhbsU8 literal 7449 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

-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 VuKLOdzo1vkpslX2mZ#zn{2zN*k%<5R diff --git a/graphics/battle_interface/z_move_trigger.png b/graphics/battle_interface/z_move_trigger.png index 7d5fbaba0f6b69918703b35c036d98fea8b51bc3..907a4cf20cb07342256db7bab6a22d0083eea591 100644 GIT binary patch delta 343 zcmV-d0jU12I_3h97=H)@0000?P=%ZT001yhOjJd=&!hPG_|)j(wYbB4pQdtbgnO5V zO=)2O0000000000`1ok(!&K3hJfwtXdSOc@d#Aww008kxL_t(YiS3lpjzb{`M6XDh z2a*2&-!|y(+E%#PzBYGWOq>xxlXD!ONdTPrD23=GfkL&`Jb!^whY0aS?h7C@5&GUD zJVHT03Z4}7;k!$F1(~(I#o@mPer{(bA9SB$o@W;kG0R&(=IKA5nX%WuxoWLryU@}q z(EsIwC-(kd_)rk^;k!#2A4ZGAPxxTge9(*!=4!2(g?zB(n_0kzyGvEadJp-q{EQF1 pcTc2z@F9EeJ>!EeU3~abJpe*J4_Zu$rLX`1002ovPDHLkV1k_Fqo@D? literal 7470 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 W7&OIyv<4^@WI{AIDAYT4=KlcOl{A$A diff --git a/src/battle_gimmick.c b/src/battle_gimmick.c index 46f2b10305..b25d97593d 100644 --- a/src/battle_gimmick.c +++ b/src/battle_gimmick.c @@ -112,12 +112,12 @@ void SetGimmickAsActivated(enum BattlerId battler, enum Gimmick gimmick) #define SINGLES_GIMMICK_TRIGGER_POS_X_OPTIMAL (30) #define SINGLES_GIMMICK_TRIGGER_POS_X_PRIORITY (31) #define SINGLES_GIMMICK_TRIGGER_POS_X_SLIDE (15) -#define SINGLES_GIMMICK_TRIGGER_POS_Y_DIFF (-11) +#define SINGLES_GIMMICK_TRIGGER_POS_Y_DIFF (-5) #define DOUBLES_GIMMICK_TRIGGER_POS_X_OPTIMAL (30) #define DOUBLES_GIMMICK_TRIGGER_POS_X_PRIORITY (31) #define DOUBLES_GIMMICK_TRIGGER_POS_X_SLIDE (15) -#define DOUBLES_GIMMICK_TRIGGER_POS_Y_DIFF (-4) +#define DOUBLES_GIMMICK_TRIGGER_POS_Y_DIFF (-2) #define tBattler data[0] #define tHide data[1] diff --git a/src/data/graphics/gimmicks.h b/src/data/graphics/gimmicks.h index c7ba9a620d..509d95ec14 100644 --- a/src/data/graphics/gimmicks.h +++ b/src/data/graphics/gimmicks.h @@ -5,7 +5,7 @@ static const u8 ALIGNED(4) sBurstTriggerGfx[] = INCGFX_U8("graphics/battle_inter static const u8 ALIGNED(4) sDynamaxTriggerGfx[] = INCGFX_U8("graphics/battle_interface/dynamax_trigger.png", ".4bpp"); static const u8 ALIGNED(4) sTeraTriggerGfx[] = INCGFX_U8("graphics/battle_interface/tera_trigger.png", ".4bpp"); -static const u16 sMegaTriggerPal[] = INCGFX_U16("graphics/battle_interface/mega_trigger.pal", ".gbapal"); +static const u16 sMegaTriggerPal[] = INCGFX_U16("graphics/battle_interface/mega_trigger.png", ".gbapal"); static const u16 sZMoveTriggerPal[] = INCGFX_U16("graphics/battle_interface/z_move_trigger.png", ".gbapal"); static const u16 sBurstTriggerPal[] = INCGFX_U16("graphics/battle_interface/burst_trigger.png", ".gbapal"); static const u16 sDynamaxTriggerPal[] = INCGFX_U16("graphics/battle_interface/dynamax_trigger.png", ".gbapal"); From af0551585d854f12d1fdabb623d6478d567c4d2d Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Wed, 29 Apr 2026 08:59:06 +0100 Subject: [PATCH 23/59] Fix typo in AddSpriteTextPrinterParameterized --- include/text.h | 2 +- src/text.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/text.h b/include/text.h index 7d2ecdb4ce..f0bda0351b 100644 --- a/include/text.h +++ b/include/text.h @@ -186,7 +186,7 @@ extern struct TextGlyph gCurGlyph; void DeactivateAllTextPrinters(void); void DeactivateSingleTextPrinter(u32 id, enum TextPrinterType type); u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); -u16 AddSpriteTextPrinterParametrerized(u8 spriteId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); +u16 AddSpriteTextPrinterParameterized(u8 spriteId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); void AddSpriteTextPrinterParameterized3(u8 spriteId, u8 fontId, u8 left, u8 top, const u8 *color, s8 speed, const u8 *str); void AddSpriteTextPrinterParameterized4(u8 spriteId, u8 fontId, u8 left, u8 top, u8 letterSpacing, u8 lineSpacing, const u8 *color, s8 speed, const u8 *str); void AddSpriteTextPrinterParameterized6(u8 spriteId, u8 fontId, u8 left, u8 top, u8 letterSpacing, u8 lineSpacing, const union TextColor color, s8 speed, const u8 *str); diff --git a/src/text.c b/src/text.c index 2fd9c9f84d..132490f415 100644 --- a/src/text.c +++ b/src/text.c @@ -385,7 +385,7 @@ u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 return AddTextPrinter(&printerTemplate, speed, callback); } -u16 AddSpriteTextPrinterParametrerized(u8 spriteId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) +u16 AddSpriteTextPrinterParameterized(u8 spriteId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) { struct TextPrinterTemplate printerTemplate; From 13450d51d13824f0368a3303d20489e09c10ace4 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 21 Apr 2026 14:04:29 +0100 Subject: [PATCH 24/59] Cleanup --- Makefile | 4 ++-- ld_script_modern.ld | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index d4c75585b4..37249891fa 100644 --- a/Makefile +++ b/Makefile @@ -105,8 +105,8 @@ ASSETS_DIR_NAME := $(BUILD_DIR)/assets ELF_NAME := $(ROM_NAME:.gba=.elf) MAP_NAME := $(ROM_NAME:.gba=.map) -TESTELF = $(ROM_NAME:.gba=-test.elf) -HEADLESSELF = $(ROM_NAME:.gba=-test-headless.elf) +TESTELF := $(ROM_NAME:.gba=-test.elf) +HEADLESSELF := $(ROM_NAME:.gba=-test-headless.elf) # Pick our active variables ROM := $(ROM_NAME) diff --git a/ld_script_modern.ld b/ld_script_modern.ld index 6141d84701..005ca633ff 100644 --- a/ld_script_modern.ld +++ b/ld_script_modern.ld @@ -70,7 +70,7 @@ SECTIONS { script_data : ALIGN(4) { - data/*.o(script_data); + data/*.o(script_data); } > ROM =0 .rodata.compound_string : From fb8eb4360e7f3bc2ee22f94af6cb0cac200af9bd Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 28 Apr 2026 13:40:29 +0100 Subject: [PATCH 25/59] Idiomatic FREE_AND_SET_NULL --- include/malloc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/malloc.h b/include/malloc.h index 10481dc398..7358e58502 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -3,10 +3,10 @@ #define FREE_AND_SET_NULL(ptr) \ -{ \ +do { \ Free(ptr); \ ptr = NULL; \ -} +} while (0) #define TRY_FREE_AND_SET_NULL(ptr) if (ptr != NULL) FREE_AND_SET_NULL(ptr) From 9ca319ceece2c24286424da21aa9ad66100c2c03 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 28 Apr 2026 09:44:51 +0100 Subject: [PATCH 26/59] preproc: pass '-s' for maps.o and map_events.o Currently makes no difference, but it's surprising not to pass it. --- map_data_rules.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/map_data_rules.mk b/map_data_rules.mk index 57752c94d3..9935171306 100755 --- a/map_data_rules.mk +++ b/map_data_rules.mk @@ -21,9 +21,9 @@ MAP_HEADERS := $(patsubst $(MAPS_DIR)/%/,$(MAPS_DIR)/%/header.inc,$(MAP_DIRS)) MAP_JSONS := $(patsubst $(MAPS_DIR)/%/,$(MAPS_DIR)/%/map.json,$(MAP_DIRS)) $(DATA_ASM_BUILDDIR)/maps.o: $(DATA_ASM_SUBDIR)/maps.s $(LAYOUTS_DIR)/layouts.inc $(LAYOUTS_DIR)/layouts_table.inc $(MAPS_DIR)/headers.inc $(MAPS_DIR)/groups.inc $(MAPS_DIR)/connections.inc $(MAP_CONNECTIONS) $(MAP_HEADERS) - $(PREPROC) $< charmap.txt | $(CPP) $(CPPFLAGS) -I include - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) -s $< charmap.txt | $(CPP) $(CPPFLAGS) -I include - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ $(DATA_ASM_BUILDDIR)/map_events.o: $(DATA_ASM_SUBDIR)/map_events.s $(MAPS_DIR)/events.inc $(MAP_EVENTS) - $(PREPROC) $< charmap.txt | $(CPP) $(CPPFLAGS) -I include - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) -s $< charmap.txt | $(CPP) $(CPPFLAGS) -I include - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ $(MAPS_OUTDIR)/%/header.inc $(MAPS_OUTDIR)/%/events.inc $(MAPS_OUTDIR)/%/connections.inc: $(MAPS_DIR)/%/map.json $(INCLUDECONSTS_OUTDIR)/map_groups.h $(MAPJSON) map emerald $< $(LAYOUTS_DIR)/layouts.json $(@D) From ecea1bc3128508495f3907be4aba12140a286fe8 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Mon, 27 Apr 2026 17:25:24 +0100 Subject: [PATCH 27/59] Fix CB2_FlashNotDetectedScreen --- src/save_failed_screen.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/save_failed_screen.c b/src/save_failed_screen.c index c2d16b0dc6..2075ae96ef 100644 --- a/src/save_failed_screen.c +++ b/src/save_failed_screen.c @@ -424,7 +424,8 @@ void CB2_FlashNotDetectedScreen(void) .height = 16, .paletteNum = 15, .baseBlock = 1, - } + }, + DUMMY_WIN_TEMPLATE }; if (gMain.state) From 4548ffca2ed06b70d7a22e23bb63655a453524cf Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Fri, 1 May 2026 06:29:28 +0100 Subject: [PATCH 28/59] Fix BattleScriptPush/Pop assertfs --- src/battle_util.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index 9a59a37e35..b3502ca091 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1241,13 +1241,19 @@ void UpdateSentPokesToOpponentValue(enum BattlerId battler) void BattleScriptPush(const u8 *bsPtr) { - assertf(gBattleResources->battleScriptsStack->size < UINT8_MAX, "attempted to push a battle script, but battleScriptsStack is full!"); + assertf(gBattleResources->battleScriptsStack->size < ARRAY_COUNT(gBattleResources->battleScriptsStack->ptr), "attempted to push a battle script, but battleScriptsStack is full!") + { + return; + } gBattleResources->battleScriptsStack->ptr[gBattleResources->battleScriptsStack->size++] = bsPtr; } void BattleScriptPushCursor(void) { - assertf(gBattleResources->battleScriptsStack->size < UINT8_MAX, "attempted to push cursor, but battleScriptsStack is full!"); + assertf(gBattleResources->battleScriptsStack->size < ARRAY_COUNT(gBattleResources->battleScriptsStack->ptr), "attempted to push cursor, but battleScriptsStack is full!") + { + return; + } gBattleResources->battleScriptsStack->ptr[gBattleResources->battleScriptsStack->size++] = gBattlescriptCurrInstr; } From ad0ed77a063881dabe87709e8ec5e2ef32726096 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Sun, 12 Apr 2026 13:19:13 +0100 Subject: [PATCH 29/59] assertfs for illegal battle controller access --- include/battle_controllers.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/battle_controllers.h b/include/battle_controllers.h index e5218e8733..fa1b50de76 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -93,46 +93,55 @@ enum BattleController static inline void MarkBattleControllerActiveOnLocal(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags |= (1u << battler); } static inline void MarkBattleControllerIdleOnLocal(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags &= ~(1u << battler); } static inline bool32 IsBattleControllerActiveOnLocal(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); return gBattleControllerExecFlags & (1u << battler); } static inline void MarkBattleControllerMessageOutboundOverLink(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags |= ((1u << battler) << (32 - MAX_BATTLERS_COUNT)); } static inline void MarkBattleControllerMessageSynchronizedOverLink(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags &= ~((1 << 28) << (battler)); } static inline bool32 IsBattleControllerMessageSynchronizedOverLink(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); return gBattleControllerExecFlags & (1u << (battler + 28)); } static inline void MarkBattleControllerActiveForPlayer(enum BattlerId battler, u32 playerId) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags |= ((1u << battler) << ((playerId) << 2)); } static inline void MarkBattleControllerIdleForPlayer(enum BattlerId battler, u32 playerId) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags &= ~((1u << battler) << ((playerId) * 4)); } static inline bool32 IsBattleControllerActiveForPlayer(enum BattlerId battler, u32 playerId) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); return gBattleControllerExecFlags & ((1u << battler) << ((playerId) * 4)); } @@ -141,6 +150,7 @@ static inline bool32 IsBattleControllerActiveForPlayer(enum BattlerId battler, u // can only be so specific before it just gets ridiculous. static inline bool32 IsBattleControllerActiveOrPendingSyncAnywhere(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); return gBattleControllerExecFlags & ( (1u << battler) | (0xF << 28) From db5d6677bc78ee920535fc429adc960fe25d1fc5 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Sun, 17 May 2026 09:48:36 +0100 Subject: [PATCH 30/59] Separate invalid/disabled species messages --- src/pokemon.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pokemon.c b/src/pokemon.c index 916ed552d7..f5e743ec2a 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -6524,7 +6524,12 @@ bool32 TryBoxMonFormChange(struct BoxPokemon *boxMon, enum FormChanges method) enum Species SanitizeSpeciesId(enum Species species) { - assertf(species <= NUM_SPECIES && (species == SPECIES_NONE || IsSpeciesEnabled(species)), "invalid species: %d", species) + assertf(species <= NUM_SPECIES, "invalid species: %d", species) + { + return SPECIES_NONE; + } + + assertf(species == SPECIES_NONE || IsSpeciesEnabled(species), "disabled species: %d", species) { return SPECIES_NONE; } From ead674344e16ec5cd9b484d62a9e4bd0a9a3db9a Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Mon, 27 Apr 2026 20:00:35 +0100 Subject: [PATCH 31/59] AllocUnchecked / AllocZeroedUnchecked / PrintHeap Alloc calls assertf, so AssertfCrashScreen must use AllocUnchecked. PrintHeap prints the contents of the heap and can be useful when investigating OOMs. --- include/malloc.h | 8 ++++++ src/assertf.c | 2 +- src/malloc.c | 65 ++++++++++++++++++++++++++++++++---------------- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/include/malloc.h b/include/malloc.h index 7358e58502..d1bd330270 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -47,19 +47,27 @@ extern u8 gHeap[HEAP_SIZE]; #if TESTING || !defined(NDEBUG) #define Alloc(size) Alloc_(size, __FILE__ ":" STR(__LINE__)) +#define AllocUnchecked(size) AllocUnchecked_(size, __FILE__ ":" STR(__LINE__)) + #define AllocZeroed(size) AllocZeroed_(size, __FILE__ ":" STR(__LINE__)) +#define AllocZeroedUnchecked(size) AllocZeroedUnchecked_(size, __FILE__ ":" STR(__LINE__)) #else #define Alloc(size) Alloc_(size, NULL) +#define AllocUnchecked(size) AllocUnchecked_(size, NULL) #define AllocZeroed(size) AllocZeroed_(size, NULL) +#define AllocZeroedUnchecked(size) AllocZeroedUnchecked_(size, NULL) #endif void *Alloc_(u32 size, const char *location); +void *AllocUnchecked_(u32 size, const char *location); void *AllocZeroed_(u32 size, const char *location); +void *AllocZeroedUnchecked_(u32 size, const char *location); void Free(void *pointer); void InitHeap(void *heapStart, u32 heapSize); +void PrintHeap(void); const struct MemBlock *HeapHead(void); const char *MemBlockLocation(const struct MemBlock *block); diff --git a/src/assertf.c b/src/assertf.c index f7ecd0fd82..43d4fc56c6 100644 --- a/src/assertf.c +++ b/src/assertf.c @@ -305,7 +305,7 @@ void AssertfCrashScreen(const void *return1, const char *fmt, ...) // Allocate on heap if possible. if (!backup) { - backup = Alloc(sizeof(*backup)); + backup = AllocUnchecked(sizeof(*backup)); if (backup) backup->onHeap = TRUE; } diff --git a/src/malloc.c b/src/malloc.c index f31c4e024e..8b3dd4bdd1 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -81,30 +81,8 @@ void *AllocInternal(void *heapStart, u32 size, const char *location) } } -#if TESTING if (pos->next == head) - { - const struct MemBlock *head = HeapHead(); - const struct MemBlock *block = head; - do - { - if (block->allocated) - { - const char *location = MemBlockLocation(block); - if (location) - Test_MgbaPrintf("%s: %d bytes allocated", location, block->size); - else - Test_MgbaPrintf(": %d bytes allocated", block->size); - } - block = block->next; - } - while (block != head); - } -#endif - assertf(pos->next != head, "%s: out of memory trying to allocate %d bytes", location, size) - { return NULL; - } pos = pos->next; } @@ -202,12 +180,55 @@ void InitHeap(void *heapStart, u32 heapSize) PutFirstMemBlockHeader(heapStart, heapSize); } +void PrintHeap(void) +{ + const struct MemBlock *head = HeapHead(); + const struct MemBlock *block = head; + do + { + if (block->allocated) + { + const char *location = MemBlockLocation(block); + if (location) + DebugPrintf("%s: %d bytes allocated", location, block->size); + else + DebugPrintf(": %d bytes allocated", block->size); + } + block = block->next; + } + while (block != head); +} + void *Alloc_(u32 size, const char *location) +{ + void *p = AllocInternal(sHeapStart, size, location); + if (!p) + { + if (TESTING) + PrintHeap(); + errorf("%s: out of memory trying to allocate %d bytes", location, size); + } + return p; +} + +void *AllocUnchecked_(u32 size, const char *location) { return AllocInternal(sHeapStart, size, location); } void *AllocZeroed_(u32 size, const char *location) +{ + void *p = AllocZeroedInternal(sHeapStart, size, location); + if (!p) + { + if (TESTING) + PrintHeap(); + errorf("%s: out of memory trying to allocate %d bytes", location, size); + } + return p; +} + +void *AllocZeroedUnchecked_(u32 size, const char *location) { return AllocZeroedInternal(sHeapStart, size, location); } From ae4fa3e933f8b2ff77b0adb903003b284eff0424 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 28 Apr 2026 08:30:46 +0100 Subject: [PATCH 32/59] malloc.c: Make internal functions static --- src/malloc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/malloc.c b/src/malloc.c index 8b3dd4bdd1..2f457bfddd 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -27,7 +27,7 @@ void PutFirstMemBlockHeader(void *block, u32 size) PutMemBlockHeader(block, (struct MemBlock *)block, (struct MemBlock *)block, size - sizeof(struct MemBlock)); } -void *AllocInternal(void *heapStart, u32 size, const char *location) +static void *AllocInternal(void *heapStart, u32 size, const char *location) { struct MemBlock *pos = (struct MemBlock *)heapStart; struct MemBlock *head = pos; @@ -88,7 +88,7 @@ void *AllocInternal(void *heapStart, u32 size, const char *location) } } -void FreeInternal(void *heapStart, void *pointer) +static void FreeInternal(void *heapStart, void *pointer) { if (pointer) { @@ -132,7 +132,7 @@ void FreeInternal(void *heapStart, void *pointer) } } -void *AllocZeroedInternal(void *heapStart, u32 size, const char *location) +static void *AllocZeroedInternal(void *heapStart, u32 size, const char *location) { void *mem = AllocInternal(heapStart, size, location); @@ -147,7 +147,7 @@ void *AllocZeroedInternal(void *heapStart, u32 size, const char *location) return mem; } -bool32 CheckMemBlockInternal(void *heapStart, void *pointer) +static bool32 CheckMemBlockInternal(void *heapStart, void *pointer) { struct MemBlock *head = (struct MemBlock *)heapStart; struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); From ec0aca7eb1aae3fb664b2997e560dd5fc3b4acd2 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Thu, 16 Apr 2026 14:40:05 +0100 Subject: [PATCH 33/59] Battle Tests: Document 'STATUS_ICON(battler, frostbite: ...)' --- include/test/battle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/test/battle.h b/include/test/battle.h index 2974fb960a..ce1455e160 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -461,7 +461,7 @@ * MESSAGE("Wobbuffet used Dream Eater!"); * MESSAGE("It doesn't affect the opposing Wobbuffet…"); * - * STATUS_ICON(battler, status1 | none: | sleep: | poison: | burn: | freeze: | paralysis:, badPoison:) + * STATUS_ICON(battler, status1 | none: | sleep: | poison: | burn: | freeze: | paralysis: | badPoison: | frostbite:) * Causes the test to fail if the battler's status is not changed to the * specified status. * STATUS_ICON(player, badPoison: TRUE); From 8f546bb922e8770852ba41990459e7a4cd2da168 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Wed, 3 Jun 2026 07:47:13 +0100 Subject: [PATCH 34/59] assertf for NULL goto/call (#10111) --- src/scrcmd.c | 4 ---- src/script.c | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/scrcmd.c b/src/scrcmd.c index 1ee2c2aece..19c012f7b9 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -88,10 +88,6 @@ extern const u8 *gStdScripts_End[]; static void CloseBrailleWindow(void); static void DynamicMultichoiceSortList(struct ListMenuItem *items, u32 count); -// This is defined in here so the optimizer can't see its value when compiling -// script.c. -void *const gNullScriptPtr = NULL; - static const u8 sScriptConditionTable[6][3] = { // < = > diff --git a/src/script.c b/src/script.c index 06aa7691a3..26a72f2cad 100644 --- a/src/script.c +++ b/src/script.c @@ -40,7 +40,6 @@ EWRAM_DATA u8 gMsgBoxIsCancelable = FALSE; extern ScrCmdFunc gScriptCmdTable[]; extern ScrCmdFunc gScriptCmdTableEnd[]; -extern void *const gNullScriptPtr; void InitScriptContext(struct ScriptContext *ctx, void *cmdTable, void *cmdTableEnd) { @@ -84,9 +83,6 @@ void StopScript(struct ScriptContext *ctx) bool8 RunScriptCommand(struct ScriptContext *ctx) { - if (ctx->mode == SCRIPT_MODE_STOPPED) - return FALSE; - switch (ctx->mode) { case SCRIPT_MODE_STOPPED: @@ -108,18 +104,12 @@ bool8 RunScriptCommand(struct ScriptContext *ctx) u8 cmdCode; ScrCmdFunc *func; - if (!ctx->scriptPtr) + if (ctx->scriptPtr == NULL) { ctx->mode = SCRIPT_MODE_STOPPED; return FALSE; } - if (ctx->scriptPtr == gNullScriptPtr) - { - while (1) - asm("svc 2"); // HALT - } - cmdCode = *(ctx->scriptPtr); ctx->scriptPtr++; func = &ctx->cmdTable[cmdCode]; @@ -163,16 +153,26 @@ static const u8 *ScriptPop(struct ScriptContext *ctx) void ScriptJump(struct ScriptContext *ctx, const u8 *ptr) { + assertf(ptr != NULL, "goto to NULL"); ctx->scriptPtr = ptr; } void ScriptCall(struct ScriptContext *ctx, const u8 *ptr) { + assertf(ptr != NULL, "call to NULL") + { + // HINT: Returning without having pushed the current location is + // equivalent to branching to a script that just contains + // 'return'. + return; + } + bool32 failed = ScriptPush(ctx, ctx->scriptPtr); assertf(!failed, "could not push %p", ptr) { return; } + ctx->scriptPtr = ptr; } From bc095cc71dbd606374bebd65e5aa097a8161fa0f Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Thu, 16 Apr 2026 13:50:53 +0100 Subject: [PATCH 35/59] Battle Tests: Faster non-headless Celebrate --- src/battle_anim.c | 39 ++++++++++++++++++++++++++++++--------- src/battle_controllers.c | 2 +- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/battle_anim.c b/src/battle_anim.c index 4dcaba3e3c..3bec8939ad 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -341,16 +341,37 @@ void LaunchBattleAnimation(u32 animType, u32 animId) if (gTestRunnerEnabled) { TestRunner_Battle_RecordAnimation(animType, animId); - // Play Transform and Ally Switch even in Headless as these move animations also change mon data. - if (gTestRunnerHeadless - #if TESTING // Because gBattleTestRunnerState is not seen outside of test env. - && !gBattleTestRunnerState->forceMoveAnim - #endif // TESTING - && !(animType == ANIM_TYPE_MOVE && (animId == MOVE_TRANSFORM || animId == MOVE_ALLY_SWITCH))) + + bool32 forceMoveAnim = FALSE; + #if TESTING // Because gBattleTestRunnerState is not seen outside of test env. + forceMoveAnim = gBattleTestRunnerState->forceMoveAnim; + #endif + if (!forceMoveAnim) { - gAnimScriptCallback = Nop; - gAnimScriptActive = FALSE; - return; + enum { DEFAULT, PLAY, SKIP } mode = DEFAULT; + if (animType == ANIM_TYPE_MOVE) + { + switch (animId) + { + // Play Transform and Ally Switch even in headless + // because the animations also change mon data. + case MOVE_TRANSFORM: + case MOVE_ALLY_SWITCH: + mode = PLAY; + break; + // Skip Celebrate even in non-headless because it's + // very noisy. + case MOVE_CELEBRATE: + mode = SKIP; + break; + } + } + if ((mode == DEFAULT && gTestRunnerHeadless) || mode == SKIP) + { + gAnimScriptCallback = Nop; + gAnimScriptActive = FALSE; + return; + } } } diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 89945ade8e..59d14c893c 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -2644,7 +2644,7 @@ void BtlController_HandlePrintString(enum BattlerId battler) if (gTestRunnerEnabled) { TestRunner_Battle_RecordMessage(gDisplayedStringBattle); - if (gTestRunnerHeadless) + if (gTestRunnerHeadless || *stringId == STRINGID_CELEBRATEMESSAGE) { BtlController_Complete(battler); return; From 68a10e3f7ea4a6560db38489ae9f05bd24015fe2 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Thu, 16 Apr 2026 10:07:26 +0100 Subject: [PATCH 36/59] Test Runner: Remove unused gBattleTrialData declaration --- include/test/battle.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/test/battle.h b/include/test/battle.h index ce1455e160..3cb7d6cbd1 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -767,8 +767,6 @@ struct BattleTrialData u8 targetTieCount; }; -extern struct BattleTrialData gBattleTrialData; - struct BattleTestData { u8 stack[BATTLE_TEST_STACK_SIZE]; From 39ebd3e736beed0db1d9f580eb72b6f8c5c1b64c Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Thu, 16 Apr 2026 12:49:35 +0100 Subject: [PATCH 37/59] Test Runner: Test_MgbaPrintf %q rounding hack --- test/test_runner.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_runner.c b/test/test_runner.c index 007ee6b21d..24ee481736 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -913,7 +913,9 @@ static s32 MgbaVPrintf_(const char *fmt, va_list va) if (++n == 2) { u *= 10; - i = MgbaPutchar_(i, '0' + ((u + UQ_4_12_ROUND) >> 12)); + // TODO: 'min' is a hack, we should have + // rounded up the previous number. + i = MgbaPutchar_(i, min('0' + ((u + UQ_4_12_ROUND) >> 12), '9')); break; } } From 9b3f9bc6bbeab7e10e8fd4545723cf4760b2c38d Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 28 Apr 2026 13:53:22 +0100 Subject: [PATCH 38/59] Test Runner: Tear down even if NULL setUp --- test/test_runner.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/test_runner.c b/test/test_runner.c index 24ee481736..7cff4b50d1 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -326,10 +326,8 @@ top: SeedRng(0); SeedRng2(0); if (gTestRunnerState.test->runner->setUp) - { gTestRunnerState.test->runner->setUp(gTestRunnerState.test->data); - gTestRunnerState.tearDown = TRUE; - } + gTestRunnerState.tearDown = TRUE; // NOTE: Assumes that the compiler interns __FILE__. if (gTestRunnerState.skipFilename == gTestRunnerState.test->filename) // Assumption fails for tests in this file. { @@ -349,10 +347,8 @@ top: gTestRunnerState.state = STATE_NEXT_TEST; if (gTestRunnerState.tearDown && gTestRunnerState.test->runner->tearDown) - { gTestRunnerState.test->runner->tearDown(gTestRunnerState.test->data); - gTestRunnerState.tearDown = FALSE; - } + gTestRunnerState.tearDown = FALSE; TestRunner_CheckMemory(); From 693483f3ead3eb5ec581aa39a2d0f045eca48bac Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 28 Apr 2026 13:53:43 +0100 Subject: [PATCH 39/59] Test Runner: Use 'enum TestResult' in 'TestRunnerState' --- include/test/test.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/test/test.h b/include/test/test.h index 9e95d837fa..df0a97a4f4 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -57,8 +57,8 @@ struct TestRunnerState const struct Test *test; u32 processCosts[MAX_PROCESSES]; - u8 result; - u8 expectedResult; + enum TestResult result:8; + enum TestResult expectedResult:8; bool8 expectLeaks:1; bool8 inBenchmark:1; bool8 tearDown:1; From 9c6b1b96edd35d44cff808b86ae258803f766bb9 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Wed, 29 Apr 2026 17:02:34 +0100 Subject: [PATCH 40/59] Test Runner: Skip assumption blocks for wholly-skipped files --- test/test_runner.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/test_runner.c b/test/test_runner.c index 7cff4b50d1..c15bbdd61e 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -277,11 +277,21 @@ top: gTestRunnerState.state = STATE_EXIT; return; } - if (gTestRunnerState.test->runner != &gAssumptionsRunner) + if (gTestRunnerState.filterMode == TEST_FILTER_MODE_FILENAME_EXACT + && !ExactMatch(gTestRunnerArgv, gTestRunnerState.test->filename)) + { + ++gTestRunnerState.test; + continue; + } + // Run all assumption blocks when filtering on test name + // because it's possible that a test in this file could + // match. + // TODO: Delay running the assumptions block until we find a + // test name that matches. + else if (gTestRunnerState.test->runner != &gAssumptionsRunner) { if ((gTestRunnerState.filterMode == TEST_FILTER_MODE_TEST_NAME_PREFIX && !PrefixMatch(gTestRunnerArgv, gTestRunnerState.test->name)) - || (gTestRunnerState.filterMode == TEST_FILTER_MODE_TEST_NAME_INFIX && !InfixMatch(gTestRunnerArgv, gTestRunnerState.test->name)) - || (gTestRunnerState.filterMode == TEST_FILTER_MODE_FILENAME_EXACT && !ExactMatch(gTestRunnerArgv, gTestRunnerState.test->filename))) + || (gTestRunnerState.filterMode == TEST_FILTER_MODE_TEST_NAME_INFIX && !InfixMatch(gTestRunnerArgv, gTestRunnerState.test->name))) { ++gTestRunnerState.test; continue; From 2ba5a5d86e7502799e615d90e84591a0ad4e1632 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 28 Apr 2026 13:54:03 +0100 Subject: [PATCH 41/59] Test Runner: Format task leaks and timeouts like memory leaks --- test/test_runner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_runner.c b/test/test_runner.c index c15bbdd61e..4e1840fb69 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -182,7 +182,7 @@ void TestRunner_CheckMemory(void) { if (gTasks[i].isActive) { - Test_MgbaPrintf(":L%s:%d - %p: task not freed", gTestRunnerState.test->filename, SourceLine(0), gTasks[i].func); + Test_MgbaPrintf(":L%s:%d: %p: task not freed", gTestRunnerState.test->filename, SourceLine(0), gTasks[i].func); gTestRunnerState.result = TEST_RESULT_FAIL; if (gTestRunnerState.expectedFailState == EXPECT_FAIL_OPEN) @@ -730,7 +730,7 @@ static void Intr_Timer2(void) if (gTestRunnerState.state == STATE_RUN_TEST) gTestRunnerState.state = STATE_REPORT_RESULT; gTestRunnerState.result = TEST_RESULT_TIMEOUT; - Test_MgbaPrintf(":L%s:%d - TIMEOUT", gTestRunnerState.test->filename, SourceLine(0)); + Test_MgbaPrintf(":L%s:%d: TIMEOUT", gTestRunnerState.test->filename, SourceLine(0)); ReinitCallbacks(); IRQ_LR = ((uintptr_t)JumpToAgbMainLoop & ~1) + 4; } From 35a45557e190cc1b7dfd3f8a28a7a3afae9ad59b Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 28 Apr 2026 13:06:15 +0100 Subject: [PATCH 42/59] Test Runner: Remove 'src/generational_changes.c' hack --- src/config_changes.c | 3 ++- test/test_runner.c | 19 ++++++++----------- test/test_runner_battle.c | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/config_changes.c b/src/config_changes.c index 06e5b6ab6a..6b4bcb65be 100644 --- a/src/config_changes.c +++ b/src/config_changes.c @@ -118,12 +118,13 @@ void SetConfig(enum ConfigTag _config, u32 _value) #if TESTING void TestInitConfigData(void) { + Free(gConfigChangesTestOverride); gConfigChangesTestOverride = Alloc(sizeof(sConfigChanges)); memcpy(gConfigChangesTestOverride, &sConfigChanges, sizeof(sConfigChanges)); } void TestFreeConfigData(void) { - TRY_FREE_AND_SET_NULL(gConfigChangesTestOverride) + FREE_AND_SET_NULL(gConfigChangesTestOverride); } #endif diff --git a/test/test_runner.c b/test/test_runner.c index 4e1840fb69..aa2790da06 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -1,6 +1,6 @@ #include -#include "fake_rtc.h" #include "global.h" +#include "fake_rtc.h" #include "gpu_regs.h" #include "load_save.h" #include "main.h" @@ -135,6 +135,8 @@ void TestRunner_CheckMemory(void) if (gTestRunnerState.result == TEST_RESULT_PASS && !gTestRunnerState.expectLeaks) { + TestFreeConfigData(); + int i; const struct MemBlock *head = HeapHead(); const struct MemBlock *block = head; @@ -154,16 +156,11 @@ void TestRunner_CheckMemory(void) const char *location = MemBlockLocation(block); if (location) { - const char cmpString[] = "src/config_changes.c"; - if (strncmp(cmpString, location, sizeof(cmpString) - 1) != 0) - { - Test_MgbaPrintf("%s: %d bytes not freed", location, block->size); - gTestRunnerState.result = TEST_RESULT_FAIL; - - if (gTestRunnerState.expectedFailState == EXPECT_FAIL_OPEN) - gTestRunnerState.expectedFailState = EXPECT_FAIL_SUCCESS; - break; - } + Test_MgbaPrintf("%s: %d bytes not freed", location, block->size); + gTestRunnerState.result = TEST_RESULT_FAIL; + + if (gTestRunnerState.expectedFailState == EXPECT_FAIL_OPEN) + gTestRunnerState.expectedFailState = EXPECT_FAIL_SUCCESS; } else { diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 372129c099..cd5ed55f58 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -290,7 +290,6 @@ static void BattleTest_SetUp(void *data) { const struct BattleTest *test = data; memset(STATE, 0, sizeof(*STATE)); - TestInitConfigData(); InvokeTestFunction(test); STATE->parameters = STATE->parametersCount; if (STATE->parametersCount == 0 && test->resultsSize > 0) @@ -382,6 +381,7 @@ static void BattleTest_Run(void *data) const struct BattleTest *test = data; memset(&DATA, 0, sizeof(DATA)); + TestInitConfigData(); DATA.recordedBattle.rngSeed = defaultSeed; DATA.recordedBattle.textSpeed = OPTIONS_TEXT_SPEED_FAST; From 8ed12e218fe7a3281bfd982ab56deedec78762cc Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Thu, 16 Apr 2026 11:02:43 +0100 Subject: [PATCH 43/59] Test Runner: Cleanup whitespace --- test/test_runner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_runner.c b/test/test_runner.c index aa2790da06..9e6b6f6e48 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -251,7 +251,7 @@ top: if (gPersistentTestRunnerState.expectCrash) gTestRunnerState.expectedResult = TEST_RESULT_CRASH; - + gTestRunnerState.expectedFailLine = 0; gTestRunnerState.expectedFailState = NO_EXPECT_FAIL; } @@ -763,7 +763,7 @@ void Test_ExitWithResult_(enum TestResult result, u32 stopLine, const void *retu gTestRunnerState.test->filename, stopLine, gTestRunnerState.expectedFailLine, stopLine); } - + ReinitCallbacks(); if (gTestRunnerState.state == STATE_REPORT_RESULT && gTestRunnerState.result != gTestRunnerState.expectedResult) From 57de63deb641a1d59f502441847ae4cc4e139833 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Sun, 19 Apr 2026 11:02:20 +0100 Subject: [PATCH 44/59] Test Runner: Use mini_printf for '%S'. When the test system was first written mini_printf couldn't be guaranteed to be linked, but it has been guaranteed for a while now. --- src/mini_printf.c | 2 +- test/test_runner.c | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/mini_printf.c b/src/mini_printf.c index 31d72dcd17..74ceb5bad5 100644 --- a/src/mini_printf.c +++ b/src/mini_printf.c @@ -47,7 +47,7 @@ struct mini_buff u32 buffer_len; }; -static inline char mini_pchar_decode(char encoded) +char mini_pchar_decode(char encoded) { char ret = '?'; if (encoded >= CHAR_a && encoded <= CHAR_z) diff --git a/test/test_runner.c b/test/test_runner.c index 9e6b6f6e48..35888132b7 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -820,8 +820,6 @@ static s32 MgbaPutchar_(s32 i, s32 c) return i; } -extern const u8 gWireless_RSEtoASCIITable[]; - // Bare-bones, only supports plain %s, %S, and %d. static s32 MgbaVPrintf_(const char *fmt, va_list va) { @@ -940,13 +938,9 @@ static s32 MgbaVPrintf_(const char *fmt, va_list va) } else { + extern char mini_pchar_decode(u8); while ((c = *pokeS++) != EOS) - { - if ((c = gWireless_RSEtoASCIITable[c]) != '\0') - i = MgbaPutchar_(i, c); - else - i = MgbaPutchar_(i, '?'); - } + i = MgbaPutchar_(i, mini_pchar_decode(c)); } break; } From 49406c8841b53b673559da7c2e893a525d496588 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Mon, 11 May 2026 10:31:54 +0100 Subject: [PATCH 45/59] InitWindows: Detect missing DUMMY_WIN_TEMPLATE terminator --- include/bg.h | 1 + include/window.h | 5 ++++- src/bg.c | 9 ++++++++- src/window.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/include/bg.h b/include/bg.h index 89ffc8d8eb..9715dfb5b4 100644 --- a/include/bg.h +++ b/include/bg.h @@ -58,6 +58,7 @@ u8 LoadBgVram(u32 bg, const void *src, u16 size, u16 destOffset, u32 mode); void SetTextModeAndHideBgs(void); bool32 IsInvalidBg(u32 bg); int BgTileAllocOp(int bg, int offset, int count, int mode); +int BgTileAllocOpUnchecked(int bg, int offset, int count, int mode); void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable); void InitBgsFromTemplates(u32 bgMode, const struct BgTemplate *templates, u8 numTemplates); void InitBgFromTemplate(const struct BgTemplate *template); diff --git a/include/window.h b/include/window.h index fc35f724d9..5af7979be4 100644 --- a/include/window.h +++ b/include/window.h @@ -48,7 +48,10 @@ struct Window ALIGNED(4) u8 *tileData; }; -bool32 InitWindows(const struct WindowTemplate *templates); +bool32 InitWindowsUnchecked(const struct WindowTemplate *templates); +bool32 InitWindowsChecked(const struct WindowTemplate *templates, s32 staticSize); +#define InitWindows(templates) InitWindowsChecked(templates, (__builtin_types_compatible_p(typeof(templates), const struct WindowTemplate *)) ? -1 : (s32)sizeof(templates)) + u32 AddWindow(const struct WindowTemplate *template); int AddWindowWithoutTileMap(const struct WindowTemplate *template); void RemoveWindow(u32 windowId); diff --git a/src/bg.c b/src/bg.c index 0ffa35f35f..45397984e8 100644 --- a/src/bg.c +++ b/src/bg.c @@ -289,8 +289,15 @@ bool32 IsInvalidBg(u32 bg) return FALSE; } -// From FRLG. Dummied out. int BgTileAllocOp(int bg, int offset, int count, int mode) +{ + int result = BgTileAllocOpUnchecked(bg, offset, count, mode); + assertf(result > 0); + return result; +} + +// From FRLG. Dummied out. +int BgTileAllocOpUnchecked(int bg, int offset, int count, int mode) { #if IS_FRLG int start, end; diff --git a/src/window.c b/src/window.c index 51b473e89c..885e802ec0 100644 --- a/src/window.c +++ b/src/window.c @@ -20,7 +20,42 @@ static void DummyWindowBgTilemap(void) } -bool32 InitWindows(const struct WindowTemplate *templates) +bool32 InitWindowsChecked(const struct WindowTemplate *templates, s32 staticSize) +{ + bool32 terminated; + + if (staticSize >= 0) + { + terminated = templates[(staticSize / sizeof(*templates)) - 1].bg == 0xFF; + } + else + { + terminated = FALSE; + for (u32 i = 0; i < WINDOWS_MAX; i++) + { + if (templates[i].bg == 0xFF) + { + terminated = TRUE; + break; + } + else if (0x04 <= templates[i].bg && templates[i].bg < 0xFF) + { + break; + } + } + } + + assertf(terminated, "%p is missing DUMMY_WIN_TEMPLATE terminator", templates) + { + return FALSE; + } + + bool32 initialized = InitWindowsUnchecked(templates); + assertf(initialized, "Could not initialize windows"); + return initialized; +} + +bool32 InitWindowsUnchecked(const struct WindowTemplate *templates) { int i; void *bgTilemapBuffer; @@ -49,7 +84,7 @@ bool32 InitWindows(const struct WindowTemplate *templates) { if (gWindowTileAutoAllocEnabled == TRUE) { - allocatedBaseBlock = BgTileAllocOp(bgLayer, 0, templates[i].width * templates[i].height, 0); + allocatedBaseBlock = BgTileAllocOpUnchecked(bgLayer, 0, templates[i].width * templates[i].height, 0); if (allocatedBaseBlock == -1) return FALSE; } @@ -60,7 +95,7 @@ bool32 InitWindows(const struct WindowTemplate *templates) if (attrib != 0xFFFF) { - allocatedTilemapBuffer = AllocZeroed(attrib); + allocatedTilemapBuffer = AllocZeroedUnchecked(attrib); if (allocatedTilemapBuffer == NULL) { @@ -76,7 +111,7 @@ bool32 InitWindows(const struct WindowTemplate *templates) } } - allocatedTilemapBuffer = AllocZeroed((u16)(32 * (templates[i].width * templates[i].height))); + allocatedTilemapBuffer = AllocZeroedUnchecked((u16)(32 * (templates[i].width * templates[i].height))); if (allocatedTilemapBuffer == NULL) { @@ -125,7 +160,7 @@ u32 AddWindow(const struct WindowTemplate *template) if (gWindowTileAutoAllocEnabled == TRUE) { - allocatedBaseBlock = BgTileAllocOp(bgLayer, 0, template->width * template->height, 0); + allocatedBaseBlock = BgTileAllocOpUnchecked(bgLayer, 0, template->width * template->height, 0); if (allocatedBaseBlock == -1) return WINDOW_NONE; From f34e315cde85b318b52e94d8ea8b54e3d4cbc77e Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Fri, 1 May 2026 06:27:58 +0100 Subject: [PATCH 46/59] Un-inline RunBattleScriptCommands --- src/battle_main.c | 6 ++---- src/battle_util.c | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/battle_main.c b/src/battle_main.c index 3d5341a824..34c10f569e 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5561,8 +5561,7 @@ static void HandleEndTurn_FinishBattle(void) } else { - if (gBattleControllerExecFlags == 0) - gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + RunBattleScriptCommands(); } } @@ -5709,8 +5708,7 @@ void RunBattleScriptCommands_PopCallbacksStack(void) } else { - if (gBattleControllerExecFlags == 0) - gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + RunBattleScriptCommands(); } } diff --git a/src/battle_util.c b/src/battle_util.c index b3502ca091..62df8743d9 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -5495,10 +5495,9 @@ void ClearVariousBattlerFlags(enum BattlerId battler) gBattleMons[battler].volatiles.grudge = FALSE; } -void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands +void HandleAction_RunBattleScript(void) { - if (gBattleControllerExecFlags == 0) - gBattleScriptingCommandsTable[*gBattlescriptCurrInstr](); + RunBattleScriptCommands(); } u32 SetRandomTarget(enum BattlerId battlerAtk) From 08c21f3c3efb98853f80cae40f6c3613544d6b57 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 12 May 2026 08:37:52 +0100 Subject: [PATCH 47/59] assertf: Support "%%" --- src/assertf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/assertf.c b/src/assertf.c index 43d4fc56c6..04e97ce472 100644 --- a/src/assertf.c +++ b/src/assertf.c @@ -236,6 +236,10 @@ static void Vprintf(const void *return1, const void *return0, const char *fmt, v char f = *fmt++; switch (f) { + case '%': + if (!Putc(&x, &y, '%')) + return; + break; case 'd': if (!Puti(&x, &y, va_arg(va, int))) return; From 17d3887310b99e3483072313d815a198a4ae0cd9 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Fri, 1 May 2026 11:12:30 +0100 Subject: [PATCH 48/59] MgbaVPrintf_/Vprintf: support for %.*s/%.*S --- src/assertf.c | 27 +++++++++++++++++++-------- test/test_runner.c | 23 ++++++++++++++++++++--- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/assertf.c b/src/assertf.c index 04e97ce472..bf2252a377 100644 --- a/src/assertf.c +++ b/src/assertf.c @@ -145,9 +145,9 @@ static bool32 Putp(u32 *x, u32 *y, const void *p) return TRUE; } -static bool32 Puts(u32 *x, u32 *y, const char *s) +static bool32 Puts(u32 *x, u32 *y, s32 n, const char *s) { - while (*s != '\0') + while (*s != '\0' && n-- > 0) { if (!Putc(x, y, *s++)) return FALSE; @@ -155,9 +155,9 @@ static bool32 Puts(u32 *x, u32 *y, const char *s) return TRUE; } -static bool32 PutS(u32 *x, u32 *y, const u8 *s) +static bool32 PutS(u32 *x, u32 *y, s32 n, const u8 *s) { - while (*s != EOS) + while (*s != EOS && n-- > 0) { char c; if (CHAR_a <= *s && *s <= CHAR_z) @@ -215,6 +215,7 @@ static bool32 Putx(u32 *x, u32 *y, unsigned u) static void Vprintf(const void *return1, const void *return0, const char *fmt, va_list va) { u32 x, y; + s32 n; x = 3; y = 19; @@ -226,6 +227,16 @@ static void Vprintf(const void *return1, const void *return0, const char *fmt, v y = 0; while (TRUE) { + if (fmt[0] == '.' && fmt[1] == '*') + { + fmt += 2; + n = va_arg(va, int); + } + else + { + n = INT_MAX; + } + char c = *fmt++; if (c == '\0') { @@ -249,11 +260,11 @@ static void Vprintf(const void *return1, const void *return0, const char *fmt, v return; break; case 's': - if (!Puts(&x, &y, va_arg(va, const char *))) + if (!Puts(&x, &y, n, va_arg(va, const char *))) return; break; case 'S': - if (!PutS(&x, &y, va_arg(va, const u8 *))) + if (!PutS(&x, &y, n, va_arg(va, const u8 *))) return; break; case 'x': @@ -269,11 +280,11 @@ static void Vprintf(const void *return1, const void *return0, const char *fmt, v } } - if (!Puts(&x, &y, "\n in: ")) + if (!Puts(&x, &y, INT_MAX, "\n in: ")) return; if (!Putp(&x, &y, return1)) return; - if (!Puts(&x, &y, "\n in: ")) + if (!Puts(&x, &y, INT_MAX, "\n in: ")) return; if (!Putp(&x, &y, return0)) return; diff --git a/test/test_runner.c b/test/test_runner.c index 35888132b7..45684247f3 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -820,10 +820,17 @@ static s32 MgbaPutchar_(s32 i, s32 c) return i; } -// Bare-bones, only supports plain %s, %S, and %d. +// Bare-bones, supports: +// - %s, %.*s: print an ASCII string. +// - %S, %.*S: print a GF-encoded string. +// - %d: print a signed integer. +// - %q: print a Q20.12 fixed-point number. +// - %p: print a pointer (which mgba-rom-test-hydra will convert into a +// symbol, if possible). static s32 MgbaVPrintf_(const char *fmt, va_list va) { s32 i = 0; + s32 n; s32 c, d; u32 p; const char *s; @@ -833,6 +840,16 @@ static s32 MgbaVPrintf_(const char *fmt, va_list va) switch ((c = *fmt++)) { case '%': + if (fmt[0] == '.' && fmt[1] == '*') + { + fmt += 2; + n = va_arg(va, int); + } + else + { + n = INT_MAX; + } + switch (*fmt++) { case '%': @@ -924,7 +941,7 @@ static s32 MgbaVPrintf_(const char *fmt, va_list va) break; case 's': s = va_arg(va, const char *); - while ((c = *s++) != '\0') + while ((c = *s++) != '\0' && n-- > 0) i = MgbaPutchar_(i, c); break; case 'S': @@ -939,7 +956,7 @@ static s32 MgbaVPrintf_(const char *fmt, va_list va) else { extern char mini_pchar_decode(u8); - while ((c = *pokeS++) != EOS) + while ((c = *pokeS++) != EOS && n-- > 0) i = MgbaPutchar_(i, mini_pchar_decode(c)); } break; From 919bcaec2c3ad535751c9fd7a6ec048848a43396 Mon Sep 17 00:00:00 2001 From: Bassoonian Date: Wed, 3 Jun 2026 14:32:48 +0200 Subject: [PATCH 49/59] Remove deprecated ``HQ_RANDOM`` config (#10131) --- include/config/general.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/config/general.h b/include/config/general.h index 6b7d3e6b79..6e4e4987e6 100644 --- a/include/config/general.h +++ b/include/config/general.h @@ -74,7 +74,6 @@ // General settings #define EXPANSION_INTRO TRUE // If TRUE, a custom RHH intro will play after the vanilla copyright screen. -#define HQ_RANDOM TRUE // If TRUE, replaces the default RNG with an implementation of SFC32 RNG. May break code that relies on RNG. #define PHONEMES_SHARED FALSE // If TRUE, bard phonemes all reference the same sound (sound/direct_sound_samples/phonemes/shared.bin) to save ROM space. // Measurement system constants to be used for UNITS From 794fbdb500e7bca77a95b80e12b5db863dbf1fc0 Mon Sep 17 00:00:00 2001 From: GGbond Date: Thu, 4 Jun 2026 19:10:08 +0800 Subject: [PATCH 50/59] Fix Beat Up typeless damage test effectiveness check (#10103) --- test/battle/move_effect/beat_up.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/battle/move_effect/beat_up.c b/test/battle/move_effect/beat_up.c index 8f8c716fe5..1f8f15b7a2 100644 --- a/test/battle/move_effect/beat_up.c +++ b/test/battle/move_effect/beat_up.c @@ -200,7 +200,7 @@ SINGLE_BATTLE_TEST("Beat Up lists each party member's name") } } -SINGLE_BATTLE_TEST("Beat Up's damage is typeless", s16 damage) +SINGLE_BATTLE_TEST("Beat Up's damage is typeless (up to Gen4)", s16 damage) { u16 defender = SPECIES_WOBBUFFET; u16 type1, type2; @@ -225,7 +225,7 @@ SINGLE_BATTLE_TEST("Beat Up's damage is typeless", s16 damage) PARAMETRIZE { defender = SPECIES_SYLVEON; } // Fairy GIVEN { - WITH_CONFIG(B_BEAT_UP, GEN_3); + WITH_CONFIG(B_BEAT_UP, GEN_4); type1 = GetSpeciesType(defender, 0); type2 = GetSpeciesType(defender, 1); ASSUME(type2 == type1 || type2 == TYPE_MYSTERY); // Ensure monotype targets @@ -235,12 +235,8 @@ SINGLE_BATTLE_TEST("Beat Up's damage is typeless", s16 damage) TURN { MOVE(player, MOVE_BEAT_UP); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player); + EFFECTIVENESS_SE(opponent, SE_EFFECTIVE); HP_BAR(opponent, captureDamage: &results[i].damage); - NONE_OF { - MESSAGE("It's super effective!"); - MESSAGE("It's not very effective..."); - MESSAGE("It doesn't affect"); - } } THEN { EXPECT_GT(results[i].damage, 0); } From a02028420cbd85cfa17f213fd6ad9cc67974649b Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Thu, 4 Jun 2026 21:20:34 +0100 Subject: [PATCH 51/59] if_comptime (#10130) --- include/metaprogram.h | 10 ++++++++++ include/random.h | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/metaprogram.h b/include/metaprogram.h index ec0b6ef0bf..d29c42571c 100644 --- a/include/metaprogram.h +++ b/include/metaprogram.h @@ -207,4 +207,14 @@ Input must be of the form (upper << lower) where upper can be up to 7, lower up /* Useful for counting arguments */ #define PLUS_ONE(...) + 1 +/* Expands to 'if (true)' if 'cond' can be evaluated at compile-time and + * evaluates to non-zero; expands to 'if (false)' otherwise. + * + * GCC will not generate code for an 'if (false) { ... }', so this can + * be used to write compile-time optimizations without a run-time cost. + * + * Because 'cond' must be known at compile-time, this is rarely useful + * outside macros. */ +#define if_comptime(cond) if (__builtin_constant_p((cond) ? 0 : *(int *)0)) + #endif diff --git a/include/random.h b/include/random.h index 41238a1ee4..35f99aad17 100644 --- a/include/random.h +++ b/include/random.h @@ -267,7 +267,11 @@ enum RandomTag #define RandomPercentage(tag, t) \ ({ \ u32 r; \ - if (t <= 0) \ + if_comptime (t == 50) \ + { \ + r = RandomUniform(tag, FALSE, TRUE); \ + } \ + else if (t <= 0) \ { \ r = FALSE; \ } \ From 8d3d8c50f9fca8598e0d540c71eda0495b64f5f9 Mon Sep 17 00:00:00 2001 From: grintoul <166724814+grintoul1@users.noreply.github.com> Date: Thu, 4 Jun 2026 22:37:56 +0200 Subject: [PATCH 52/59] Prevent AI illegally targeting itself in doubles (#10139) --- src/battle_ai_main.c | 2 +- test/battle/ai/ai.c | 90 ++++++++++++++++++++++++++++++++++++ test/battle/trainer_slides.c | 15 +++--- 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 01b6ff17e5..2b7976f135 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -929,7 +929,7 @@ static u32 ChooseMoveOrAction_Doubles(enum BattlerId battler) for (enum BattlerId battlerIndex = 0; battlerIndex < MAX_BATTLERS_COUNT; battlerIndex++) { - if (gBattleMons[battlerIndex].hp == 0) + if (gBattleMons[battlerIndex].hp == 0 || battler == battlerIndex) { actionOrMoveIndex[battlerIndex] = 0xFF; bestMovePointsForTarget[battlerIndex] = -1; diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index 6fc6610edd..17dacaf148 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -1355,3 +1355,93 @@ AI_DOUBLE_BATTLE_TEST("Bolt Beak damage will be correctly seen by AI (doubles)") } } } + +AI_MULTI_BATTLE_TEST("AI does not target itself with selected moves in doubles (TARGET_SELECTED)") +{ + PASSES_RANDOMLY(100, 100, RNG_AI_SCORE_TIE_DOUBLES_TARGET); + + GIVEN { + ASSUME(GetMoveTarget(MOVE_FLAMETHROWER) == TARGET_SELECTED); + AI_FLAGS(0); + TIE_BREAK_TARGET(TARGET_TIE_CHOSEN, i % 3); + PLAYER(SPECIES_TURTONATOR) { Speed(4); } + PARTNER(SPECIES_TURTONATOR) { Speed(2); Moves(MOVE_FLAMETHROWER); } + OPPONENT_A(SPECIES_TURTONATOR) { Speed(3); Moves(MOVE_FLAMETHROWER); } + OPPONENT_B(SPECIES_TURTONATOR) { Speed(1); Moves(MOVE_FLAMETHROWER); } + } WHEN { + TURN { + EXPECT_MOVE(opponentLeft, MOVE_FLAMETHROWER); + EXPECT_MOVE(playerRight, MOVE_FLAMETHROWER); + EXPECT_MOVE(opponentRight, MOVE_FLAMETHROWER); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLAMETHROWER, opponentLeft); + NOT HP_BAR(opponentLeft); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLAMETHROWER, playerRight); + NOT HP_BAR(playerRight); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLAMETHROWER, opponentRight); + NOT HP_BAR(opponentRight); + } +} + +AI_MULTI_BATTLE_TEST("AI does not target itself with selected moves in doubles (TARGET_FOES_AND_ALLY)") +{ + PASSES_RANDOMLY(100, 100, RNG_AI_SCORE_TIE_DOUBLES_TARGET); + + GIVEN { + ASSUME(GetMoveTarget(MOVE_LAVA_PLUME) == TARGET_FOES_AND_ALLY); + AI_FLAGS(0); + TIE_BREAK_TARGET(TARGET_TIE_CHOSEN, i % 3); + PLAYER(SPECIES_TURTONATOR) { Speed(4); } + PARTNER(SPECIES_TURTONATOR) { Speed(2); Moves(MOVE_LAVA_PLUME); } + OPPONENT_A(SPECIES_TURTONATOR) { Speed(3); Moves(MOVE_LAVA_PLUME); } + OPPONENT_B(SPECIES_TURTONATOR) { Speed(1); Moves(MOVE_LAVA_PLUME); } + } WHEN { + TURN { + EXPECT_MOVE(opponentLeft, MOVE_LAVA_PLUME); + EXPECT_MOVE(playerRight, MOVE_LAVA_PLUME); + EXPECT_MOVE(opponentRight, MOVE_LAVA_PLUME); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_LAVA_PLUME, opponentLeft); + NOT HP_BAR(opponentLeft); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_LAVA_PLUME, playerRight); + NOT HP_BAR(playerRight); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_LAVA_PLUME, opponentRight); + NOT HP_BAR(opponentRight); + } +} + +AI_MULTI_BATTLE_TEST("AI does not target itself with selected moves in doubles (TARGET_BOTH)") +{ + PASSES_RANDOMLY(100, 100, RNG_AI_SCORE_TIE_DOUBLES_TARGET); + + GIVEN { + ASSUME(GetMoveTarget(MOVE_HEAT_WAVE) == TARGET_BOTH); + AI_FLAGS(0); + TIE_BREAK_TARGET(TARGET_TIE_CHOSEN, i % 3); + PLAYER(SPECIES_TURTONATOR) { Speed(4); } + PARTNER(SPECIES_TURTONATOR) { Speed(2); Moves(MOVE_HEAT_WAVE); } + OPPONENT_A(SPECIES_TURTONATOR) { Speed(3); Moves(MOVE_HEAT_WAVE); } + OPPONENT_B(SPECIES_TURTONATOR) { Speed(1); Moves(MOVE_HEAT_WAVE); } + } WHEN { + TURN { + EXPECT_MOVE(opponentLeft, MOVE_HEAT_WAVE); + EXPECT_MOVE(playerRight, MOVE_HEAT_WAVE); + EXPECT_MOVE(opponentRight, MOVE_HEAT_WAVE); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAT_WAVE, opponentLeft); + NOT HP_BAR(opponentLeft); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAT_WAVE, playerRight); + NOT HP_BAR(playerRight); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAT_WAVE, opponentRight); + NOT HP_BAR(opponentRight); + } +} diff --git a/test/battle/trainer_slides.c b/test/battle/trainer_slides.c index e0d4306617..65ec51ba6b 100644 --- a/test/battle/trainer_slides.c +++ b/test/battle/trainer_slides.c @@ -272,7 +272,7 @@ AI_DOUBLE_BATTLE_TEST("Trainer Slide: Doubles: Enemy Lands First Critical Hit") OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } } WHEN { - TURN { EXPECT_MOVE(opponentLeft, MOVE_SURGING_STRIKES, target: playerLeft); } + TURN { EXPECT_MOVE(opponentLeft, MOVE_SURGING_STRIKES); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_SURGING_STRIKES, opponentLeft); MESSAGE("A critical hit!"); @@ -554,8 +554,8 @@ AI_MULTI_BATTLE_TEST("Trainer Slide: Multi: Enemy Lands First Critical Hit") OPPONENT_B(SPECIES_WOBBUFFET) { Speed(3); } } WHEN { TURN { MOVE(playerLeft, MOVE_ENDURE); - EXPECT_MOVE(opponentLeft, MOVE_SURGING_STRIKES, target: playerLeft); - EXPECT_MOVE(opponentRight, MOVE_SURGING_STRIKES, target: playerLeft); + EXPECT_MOVE(opponentLeft, MOVE_SURGING_STRIKES); + EXPECT_MOVE(opponentRight, MOVE_SURGING_STRIKES); MOVE(playerRight, MOVE_SURGING_STRIKES, target: playerLeft); } } SCENE { @@ -692,9 +692,9 @@ AI_MULTI_BATTLE_TEST("Trainer Slide: Multi: Last Switchin") OPPONENT_B(SPECIES_WOBBUFFET) { Speed(2); Moves(MOVE_CELEBRATE); } } WHEN { TURN { - EXPECT_MOVE(opponentLeft, MOVE_MEMENTO, target: playerRight); EXPECT_SEND_OUT(opponentLeft,1); + EXPECT_MOVE(opponentLeft, MOVE_MEMENTO); EXPECT_SEND_OUT(opponentLeft,1); MOVE(playerRight, MOVE_MEMENTO, target: opponentRight); SEND_OUT(playerRight,1); - EXPECT_MOVE(opponentRight, MOVE_MEMENTO, target: playerRight); EXPECT_SEND_OUT(opponentRight,1); + EXPECT_MOVE(opponentRight, MOVE_MEMENTO); EXPECT_SEND_OUT(opponentRight,1); } } SCENE { MESSAGE("The opposing Wobbuffet fainted!"); @@ -786,9 +786,9 @@ AI_MULTI_BATTLE_TEST("Trainer Slide: Multi: Z Move") OPPONENT_A(SPECIES_WOBBUFFET) { Speed(3); Item(ITEM_NORMALIUM_Z); } OPPONENT_B(SPECIES_WOBBUFFET) { Speed(1); Item(ITEM_NORMALIUM_Z); } } WHEN { - TURN { EXPECT_MOVE(opponentLeft, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE, target: playerLeft); + TURN { EXPECT_MOVE(opponentLeft, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); MOVE(playerRight, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE, target: opponentLeft); - EXPECT_MOVE(opponentRight, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE, target: playerLeft); } + EXPECT_MOVE(opponentRight, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); } } SCENE { MESSAGE("Trainer A: This message plays before the enemy activates the Z-Move gimmick.{PAUSE_UNTIL_PRESS}"); MESSAGE("The opposing Wobbuffet surrounded itself with its Z-Power!"); @@ -848,4 +848,5 @@ AI_MULTI_BATTLE_TEST("Trainer Slide: Multi: Dynamax") } } } + // MULTI TESTS END From 9099db974405a2e7d504398ffec253669587bc68 Mon Sep 17 00:00:00 2001 From: Viperio <146665252+Viperio19@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:16:10 +0200 Subject: [PATCH 53/59] Fix player's hp display showing 0 max hp for p2 in link battles after taking damage (#10105) --- src/battle_controllers.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 59d14c893c..97dcf98552 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -2166,11 +2166,13 @@ static void Controller_HandleTrainerSlideBack(enum BattlerId battler) void Controller_WaitForHealthBar(enum BattlerId battler) { s16 hpValue = MoveBattleBar(battler, gHealthboxSpriteIds[battler], HEALTH_BAR, 0); + struct Pokemon *mon = GetBattlerMon(battler); + s32 maxHP = GetMonData(mon, MON_DATA_MAX_HP); SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]); if (hpValue != -1) { - UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, hpValue, gBattleMons[battler].maxHP); + UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, hpValue, maxHP); } else { From 41467c049ee60afb1a41d62fb95e0a3a9dd44889 Mon Sep 17 00:00:00 2001 From: GGbond Date: Sat, 6 Jun 2026 14:26:25 +0800 Subject: [PATCH 54/59] Fix generic ability ineffective battle message misuse (#10149) --- src/battle_message.c | 4 ++-- test/battle/ability/flash_fire.c | 2 ++ test/battle/ability/insomnia.c | 1 + test/battle/ability/shadow_tag.c | 15 +++++++++++++++ test/battle/ability/vital_spirit.c | 20 ++++++++++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/battle_message.c b/src/battle_message.c index 6f44b22abc..b445f4a756 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -495,7 +495,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNSITEMNORMALIZEDSTATUS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_LAST_ITEM} normalized its status!"), // Not in Gen 5+ [STRINGID_TRAINER1USEDITEM] = COMPOUND_STRING("{B_ATK_TRAINER_NAME_WITH_CLASS} used {B_LAST_ITEM}!"), [STRINGID_BOXISFULL] = COMPOUND_STRING("The Box is full! You can't catch any more!\p"), - [STRINGID_PKMNSXMADEITINEFFECTIVE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s item cannot be removed!"), + [STRINGID_PKMNSXMADEITINEFFECTIVE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} made it ineffective!"), [STRINGID_PKMNSXPREVENTSFLINCHING] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s {B_EFF_ABILITY} prevents flinching!"), //not in gen 5+, ability popup [STRINGID_PKMNALREADYHASBURN] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is already burned!"), [STRINGID_PKMNSXBLOCKSY] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} blocks {B_CURRENT_MOVE}!"), //not in gen 5+, ability popup @@ -1352,7 +1352,7 @@ const u16 gItemSwapStringIds[] = const u16 gFlashFireStringIds[] = { [B_MSG_FLASH_FIRE_BOOST] = STRINGID_PKMNRAISEDFIREPOWERWITH, - [B_MSG_FLASH_FIRE_NO_BOOST] = STRINGID_PKMNSXMADEYINEFFECTIVE + [B_MSG_FLASH_FIRE_NO_BOOST] = STRINGID_PKMNSXMADEITINEFFECTIVE }; const u16 gCaughtMonStringIds[] = diff --git a/test/battle/ability/flash_fire.c b/test/battle/ability/flash_fire.c index 4cdcec9973..3b7d7bbb0b 100644 --- a/test/battle/ability/flash_fire.c +++ b/test/battle/ability/flash_fire.c @@ -16,9 +16,11 @@ SINGLE_BATTLE_TEST("Flash Fire boosts fire type moves by 50% but no subsequent i ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); HP_BAR(opponent, captureDamage: &damage[0]); ABILITY_POPUP(player, ABILITY_FLASH_FIRE); + MESSAGE("The power of Heatran's Fire-type moves rose!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); HP_BAR(opponent, captureDamage: &damage[1]); ABILITY_POPUP(player, ABILITY_FLASH_FIRE); + MESSAGE("Heatran made it ineffective!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); HP_BAR(opponent, captureDamage: &damage[2]); } THEN { diff --git a/test/battle/ability/insomnia.c b/test/battle/ability/insomnia.c index c95b294907..f012c90ec1 100644 --- a/test/battle/ability/insomnia.c +++ b/test/battle/ability/insomnia.c @@ -12,6 +12,7 @@ SINGLE_BATTLE_TEST("Insomnia prevents sleep") TURN { MOVE(opponent, MOVE_SPORE); } } SCENE { ABILITY_POPUP(player, ABILITY_INSOMNIA); + MESSAGE("Drowzee made it ineffective!"); NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, player); diff --git a/test/battle/ability/shadow_tag.c b/test/battle/ability/shadow_tag.c index f00696d8b7..93b930ecb3 100644 --- a/test/battle/ability/shadow_tag.c +++ b/test/battle/ability/shadow_tag.c @@ -2,3 +2,18 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Shadow Tag (Ability) test titles") + +WILD_BATTLE_TEST("Shadow Tag prevents wild Pokemon from fleeing with Teleport") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_TELEPORT) == EFFECT_TELEPORT); + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SHADOW_TAG); } + OPPONENT(SPECIES_ABRA); + } WHEN { + TURN { MOVE(opponent, MOVE_TELEPORT); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TELEPORT, opponent); + ABILITY_POPUP(player, ABILITY_SHADOW_TAG); + MESSAGE("Wobbuffet made it ineffective!"); + } +} diff --git a/test/battle/ability/vital_spirit.c b/test/battle/ability/vital_spirit.c index 2539df2334..85fcbff613 100644 --- a/test/battle/ability/vital_spirit.c +++ b/test/battle/ability/vital_spirit.c @@ -2,3 +2,23 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Vital Spirit (Ability) test titles") + +SINGLE_BATTLE_TEST("Vital Spirit prevents sleep") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_SPORE) == MOVE_EFFECT_SLEEP); + PLAYER(SPECIES_MANKEY) { Ability(ABILITY_VITAL_SPIRIT); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SPORE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_VITAL_SPIRIT); + MESSAGE("Mankey made it ineffective!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, player); + STATUS_ICON(player, sleep: TRUE); + } + } +} From a59a30d0319f226ad54feb99214ad402cd327bf1 Mon Sep 17 00:00:00 2001 From: Marky <143505183+HashtagMarky@users.noreply.github.com> Date: Sat, 6 Jun 2026 08:16:41 +0100 Subject: [PATCH 55/59] Fix HGSS Dex Form Strings (#10147) --- src/pokedex_plus_hgss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index d8bf90ce00..8240941065 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -224,9 +224,9 @@ static const u8 sText_EVO_DEFEAT_THREE_WITH_ITEM[] = _("{LV}{UP_ARROW} defeating static const u8 sText_EVO_NONE[] = _("{STR_VAR_1} has no evolution."); static const u8 sText_FORMS_Buttons_PE[] = _("{A_BUTTON}FORM MODE {START_BUTTON}EVOs"); -static const u8 sText_FORMS_Buttons_Decapped_PE[] = _("{START_BUTTON}Evos"); +static const u8 sText_FORMS_Buttons_Decapped_PE[] = _("{A_BUTTON}Form Mode {START_BUTTON}Evos"); static const u8 sText_FORMS_Buttons_Submenu_PE[] = _("{DPAD_NONE}FORMs {A_BUTTON}CHECK {START_BUTTON}EVOs"); -static const u8 sText_FORMS_Buttons_Submenu_Decapped_PE[] = _("{START_BUTTON}Evos"); +static const u8 sText_FORMS_Buttons_Submenu_Decapped_PE[] = _("{DPAD_NONE}Forms {A_BUTTON}Check {START_BUTTON}Evos"); static const u8 sText_FORMS_NONE[] = _("{STR_VAR_1} has no alternate forms."); static const u8 sText_PlusSymbol[] = _("+"); From 983a884ab887d908f8712f027d424039c0b8cc50 Mon Sep 17 00:00:00 2001 From: Hedara Date: Sat, 6 Jun 2026 16:46:57 +0200 Subject: [PATCH 56/59] Expansion 1.16.1 release --- .../ISSUE_TEMPLATE/01_battle_engine_bugs.yaml | 3 +- .../ISSUE_TEMPLATE/02_battle_ai_issues.yaml | 3 +- .github/ISSUE_TEMPLATE/04_other_errors.yaml | 3 +- README.md | 2 +- docs/SUMMARY.md | 1 + docs/changelogs/1.16.x/1.16.1.md | 90 +++++++++++++++++++ include/constants/expansion.h | 4 +- 7 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 docs/changelogs/1.16.x/1.16.1.md diff --git a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml index 42a31171b7..dc13c04856 100644 --- a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml +++ b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml @@ -43,9 +43,10 @@ body: label: Version description: What version of pokeemerald-expansion are you using? options: - - 1.16.0 (Latest release) + - 1.16.1 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.16.0 - 1.15.3 - 1.15.2 - 1.15.1 diff --git a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml index 28943effda..48f3793e6d 100644 --- a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml +++ b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml @@ -43,9 +43,10 @@ body: label: Version description: What version of pokeemerald-expansion are you using? options: - - 1.16.0 (Latest release) + - 1.16.1 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.16.0 - 1.15.3 - 1.15.2 - 1.15.1 diff --git a/.github/ISSUE_TEMPLATE/04_other_errors.yaml b/.github/ISSUE_TEMPLATE/04_other_errors.yaml index cda4d6dc2f..3c7bd9cf70 100644 --- a/.github/ISSUE_TEMPLATE/04_other_errors.yaml +++ b/.github/ISSUE_TEMPLATE/04_other_errors.yaml @@ -43,9 +43,10 @@ body: label: Version description: What version of pokeemerald-expansion are you using? options: - - 1.16.0 (Latest release) + - 1.16.1 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.16.0 - 1.15.3 - 1.15.2 - 1.15.1 diff --git a/README.md b/README.md index c768a6f5d8..0c4eac3dc1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you use **`pokeemerald-expansion`**, please credit **RHH (Rom Hacking Hideout)**. Optionally, include the version number for clarity. ``` -Based off RHH's pokeemerald-expansion 1.16.0 https://github.com/rh-hideout/pokeemerald-expansion/ +Based off RHH's pokeemerald-expansion 1.16.1 https://github.com/rh-hideout/pokeemerald-expansion/ ``` Please consider [crediting all contributors](CREDITS.md) involved in the project! diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 29ba69a290..fea1483cde 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -56,6 +56,7 @@ - [How to use Random Mon Generation](tutorials/how_to_random_mon_generator.md) - [Changelog](./CHANGELOG.md) - [1.16.x]() + - [Version 1.16.1](changelogs/1.16.x/1.16.1.md) - [Version 1.16.0](changelogs/1.16.x/1.16.0.md) - [1.15.x]() - [Version 1.15.3](changelogs/1.15.x/1.15.3.md) diff --git a/docs/changelogs/1.16.x/1.16.1.md b/docs/changelogs/1.16.x/1.16.1.md new file mode 100644 index 0000000000..4ab9c54104 --- /dev/null +++ b/docs/changelogs/1.16.x/1.16.1.md @@ -0,0 +1,90 @@ +```md +## How to update +- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`. +- Once you have your remote set up, run the command `git pull RHH expansion/1.16.1 +`. +``` + + +## 🧬 General 🧬 +### Added +* Add `if_comptime` by @mrgriffin in [#10130](https://github.com/rh-hideout/pokeemerald-expansion/pull/10130) + +### Changed +* Cleanup 'message 0x0' by @mrgriffin in [#10110](https://github.com/rh-hideout/pokeemerald-expansion/pull/10110) +* Fix Trainer Party Pool documentation by @RubyRaven6 in [#10122](https://github.com/rh-hideout/pokeemerald-expansion/pull/10122) +* Remove deprecated ``HQ_RANDOM`` config by @Bassoonian in [#10131](https://github.com/rh-hideout/pokeemerald-expansion/pull/10131) + +### Fixed +* chore(credits): change kildemal to miriam in credits by @miriamlefae in [#10123](https://github.com/rh-hideout/pokeemerald-expansion/pull/10123) +* Misc Fixes/Cleanups by @mrgriffin in [#9892](https://github.com/rh-hideout/pokeemerald-expansion/pull/9892) +* Fix HGSS Dex Form Strings by @HashtagMarky in [#10147](https://github.com/rh-hideout/pokeemerald-expansion/pull/10147) + +## 🗺️ Overworld 🗺️ +### Changed +* assertf for NULL goto/call by @mrgriffin in [#10111](https://github.com/rh-hideout/pokeemerald-expansion/pull/10111) + +### Fixed +* Fix colosseum warps frlg by @Viperio19 in [#10100](https://github.com/rh-hideout/pokeemerald-expansion/pull/10100) + +## 🐉 Pokémon 🐉 +### Changed +* Fix missing incgfx for Mega Garchomp Z by @hedara90 in [#10116](https://github.com/rh-hideout/pokeemerald-expansion/pull/10116) + +## ⚔️ Battle General ⚔️ +### Changed +* feat (battle): improve gimmick triggers' graphics by @mudskipper13 in [#10129](https://github.com/rh-hideout/pokeemerald-expansion/pull/10129) + +### Fixed +* Fixes stat change queue having erroneous stats stored by @AlexOn1ine in [#10088](https://github.com/rh-hideout/pokeemerald-expansion/pull/10088) +* Fixes Acupressure timeout in doubles by @AlexOn1ine in [#10091](https://github.com/rh-hideout/pokeemerald-expansion/pull/10091) +* Fixes Random Move from disobedience by @AlexOn1ine in [#10093](https://github.com/rh-hideout/pokeemerald-expansion/pull/10093) +* Fix link singles and doubles using incorrect parties by @Viperio19 in [#10102](https://github.com/rh-hideout/pokeemerald-expansion/pull/10102) +* Fix player's hp display showing 0 max hp for p2 in link battles after taking damage by @Viperio19 in [#10105](https://github.com/rh-hideout/pokeemerald-expansion/pull/10105) +* Fix generic ability ineffective battle message misuse by @Cle-bit in [#10149](https://github.com/rh-hideout/pokeemerald-expansion/pull/10149) + +## 🧶 Items 🧶 +### Changed +* Add missing item sort types by @Cle-bit in [#10104](https://github.com/rh-hideout/pokeemerald-expansion/pull/10104) +* SanitizeBagItemId, TryTakeMonItemResult by @mrgriffin in [#10109](https://github.com/rh-hideout/pokeemerald-expansion/pull/10109) + +### Fixed +* Use values from `enum PokeBall` for Poké Balls by @PCG06 in [#10106](https://github.com/rh-hideout/pokeemerald-expansion/pull/10106) + +## 🤖 Battle AI 🤖 +### Fixed +* Prevent AI illegally targeting itself in doubles by @grintoul1 in [#10139](https://github.com/rh-hideout/pokeemerald-expansion/pull/10139) + +## 🧹 Other Cleanup 🧹 +* Add missing item sort types by @Cle-bit in [#10104](https://github.com/rh-hideout/pokeemerald-expansion/pull/10104) +* Cleanup 'message 0x0' by @mrgriffin in [#10110](https://github.com/rh-hideout/pokeemerald-expansion/pull/10110) +* SanitizeBagItemId, TryTakeMonItemResult by @mrgriffin in [#10109](https://github.com/rh-hideout/pokeemerald-expansion/pull/10109) +* feat (battle): improve gimmick triggers' graphics by @mudskipper13 in [#10129](https://github.com/rh-hideout/pokeemerald-expansion/pull/10129) +* assertf for NULL goto/call by @mrgriffin in [#10111](https://github.com/rh-hideout/pokeemerald-expansion/pull/10111) +* Remove deprecated ``HQ_RANDOM`` config by @Bassoonian in [#10131](https://github.com/rh-hideout/pokeemerald-expansion/pull/10131) +* Fix Beat Up typeless damage test effectiveness check by @Cle-bit in [#10103](https://github.com/rh-hideout/pokeemerald-expansion/pull/10103) + +## 🧪 Test Runner 🧪 +### Changed +* Fix Beat Up typeless damage test effectiveness check by @Cle-bit in [#10103](https://github.com/rh-hideout/pokeemerald-expansion/pull/10103) + +### Fixed +* Prevent AI illegally targeting itself in doubles by @grintoul1 in [#10139](https://github.com/rh-hideout/pokeemerald-expansion/pull/10139) + +## 📚 Documentation 📚 +* Fix Trainer Party Pool documentation by @RubyRaven6 in [#10122](https://github.com/rh-hideout/pokeemerald-expansion/pull/10122) +* Fix broken/old links in CREDITS.md by @ThePeeps191 in [#10120](https://github.com/rh-hideout/pokeemerald-expansion/pull/10120) + +## 📦 Branch Synchronisation 📦 +### pret +* 1st of June, 2026 in [#10113](https://github.com/rh-hideout/pokeemerald-expansion/pull/10113) + * Implicit waitstate for special/specialvars by @mrgriffin in [pret#2200](https://github.com/pret/pokeemerald/pull/2200) + +## New Contributors +* @Viperio19 made their first contribution in [#10100](https://github.com/rh-hideout/pokeemerald-expansion/pull/10100) + +**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.16.0...expansion/1.16.1 + + + + diff --git a/include/constants/expansion.h b/include/constants/expansion.h index be34cb6c6b..b1deea84fd 100644 --- a/include/constants/expansion.h +++ b/include/constants/expansion.h @@ -1,13 +1,13 @@ #ifndef GUARD_CONSTANTS_EXPANSION_H #define GUARD_CONSTANTS_EXPANSION_H -// Last version: 1.16.0 +// Last version: 1.16.1 #define EXPANSION_VERSION_MAJOR 1 #define EXPANSION_VERSION_MINOR 16 #define EXPANSION_VERSION_PATCH 1 // FALSE if this this version of Expansion is not a tagged commit, i.e. // it contains unreleased changes. -#define EXPANSION_TAGGED_RELEASE FALSE +#define EXPANSION_TAGGED_RELEASE TRUE #endif From 2b6ee46ea66d944b14f5ab8a5da911f2a6bee615 Mon Sep 17 00:00:00 2001 From: Hedara Date: Sat, 6 Jun 2026 16:47:21 +0200 Subject: [PATCH 57/59] Start of 1.16.2 cycle --- include/constants/expansion.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/constants/expansion.h b/include/constants/expansion.h index b1deea84fd..416beca963 100644 --- a/include/constants/expansion.h +++ b/include/constants/expansion.h @@ -4,10 +4,10 @@ // Last version: 1.16.1 #define EXPANSION_VERSION_MAJOR 1 #define EXPANSION_VERSION_MINOR 16 -#define EXPANSION_VERSION_PATCH 1 +#define EXPANSION_VERSION_PATCH 2 // FALSE if this this version of Expansion is not a tagged commit, i.e. // it contains unreleased changes. -#define EXPANSION_TAGGED_RELEASE TRUE +#define EXPANSION_TAGGED_RELEASE FALSE #endif From 1855e009a695925b68e8a563b56f404a929a5a9c Mon Sep 17 00:00:00 2001 From: Tacobell24 <128149957+Tacobell24@users.noreply.github.com> Date: Sun, 7 Jun 2026 04:44:05 +0930 Subject: [PATCH 58/59] More Gen VII animation data added (#10141) --- graphics/pokemon/bounsweet/anim_front.png | Bin 0 -> 563 bytes graphics/pokemon/bounsweet/front.png | Bin 388 -> 0 bytes graphics/pokemon/bruxish/anim_front.png | Bin 0 -> 908 bytes graphics/pokemon/bruxish/front.png | Bin 571 -> 0 bytes graphics/pokemon/comfey/anim_front.png | Bin 0 -> 976 bytes graphics/pokemon/comfey/front.png | Bin 790 -> 0 bytes graphics/pokemon/cosmog/anim_front.png | Bin 0 -> 914 bytes graphics/pokemon/cosmog/front.png | Bin 616 -> 0 bytes graphics/pokemon/dhelmise/anim_front.png | Bin 0 -> 1261 bytes graphics/pokemon/dhelmise/front.png | Bin 903 -> 0 bytes graphics/pokemon/fomantis/anim_front.png | Bin 0 -> 700 bytes graphics/pokemon/fomantis/front.png | Bin 564 -> 0 bytes graphics/pokemon/komala/anim_front.png | Bin 0 -> 818 bytes graphics/pokemon/komala/front.png | Bin 616 -> 0 bytes graphics/pokemon/morelull/anim_front.png | Bin 0 -> 660 bytes graphics/pokemon/morelull/front.png | Bin 506 -> 0 bytes graphics/pokemon/palossand/anim_front.png | Bin 0 -> 1278 bytes graphics/pokemon/palossand/front.png | Bin 884 -> 0 bytes graphics/pokemon/sandygast/anim_front.png | Bin 0 -> 725 bytes graphics/pokemon/sandygast/front.png | Bin 529 -> 0 bytes graphics/pokemon/shiinotic/anim_front.png | Bin 0 -> 1230 bytes graphics/pokemon/shiinotic/front.png | Bin 793 -> 0 bytes graphics/pokemon/steenee/anim_front.png | Bin 0 -> 911 bytes graphics/pokemon/steenee/front.png | Bin 651 -> 0 bytes graphics/pokemon/tsareena/anim_front.png | Bin 0 -> 1254 bytes graphics/pokemon/tsareena/front.png | Bin 849 -> 0 bytes src/data/graphics/pokemon.h | 26 ++--- .../pokemon/species_info/gen_7_families.h | 98 ++++++++++++++---- 28 files changed, 90 insertions(+), 34 deletions(-) create mode 100644 graphics/pokemon/bounsweet/anim_front.png delete mode 100644 graphics/pokemon/bounsweet/front.png create mode 100644 graphics/pokemon/bruxish/anim_front.png delete mode 100644 graphics/pokemon/bruxish/front.png create mode 100644 graphics/pokemon/comfey/anim_front.png delete mode 100644 graphics/pokemon/comfey/front.png create mode 100644 graphics/pokemon/cosmog/anim_front.png delete mode 100644 graphics/pokemon/cosmog/front.png create mode 100644 graphics/pokemon/dhelmise/anim_front.png delete mode 100644 graphics/pokemon/dhelmise/front.png create mode 100644 graphics/pokemon/fomantis/anim_front.png delete mode 100644 graphics/pokemon/fomantis/front.png create mode 100644 graphics/pokemon/komala/anim_front.png delete mode 100644 graphics/pokemon/komala/front.png create mode 100644 graphics/pokemon/morelull/anim_front.png delete mode 100644 graphics/pokemon/morelull/front.png create mode 100644 graphics/pokemon/palossand/anim_front.png delete mode 100644 graphics/pokemon/palossand/front.png create mode 100644 graphics/pokemon/sandygast/anim_front.png delete mode 100644 graphics/pokemon/sandygast/front.png create mode 100644 graphics/pokemon/shiinotic/anim_front.png delete mode 100644 graphics/pokemon/shiinotic/front.png create mode 100644 graphics/pokemon/steenee/anim_front.png delete mode 100644 graphics/pokemon/steenee/front.png create mode 100644 graphics/pokemon/tsareena/anim_front.png delete mode 100644 graphics/pokemon/tsareena/front.png diff --git a/graphics/pokemon/bounsweet/anim_front.png b/graphics/pokemon/bounsweet/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..d9a30f545d5269aa539569d0e3072a7c274a42b7 GIT binary patch literal 563 zcmV-30?hr1P)8-?fXlP-j%}E@<(^D5nX?v z0*>zw)j)r6x7Xf!(7@}6deHRSKlF#tAAk44ofy`glX(f`7zFr)xX!q+ zKp{cFqr)NNK!SjPz>SQC9Ud7C8V)a3?Dzo$4>W#sbVOt%>^N`$$OCGc!z@$;G>6I4 z#W5tJ_3c#4ro#$6u7VjKeHwntn=2&DS-Mdnv@JgJXthv+^z*W^vVHap8;<=JU8^qiabD)M*}hsNKvYAJ0L)FycJT5G{+sG zV({w-6tnyL$@L7p)i;=#L}Y~uRKWOPvEAW7Z4Znc_p)Im0u|UfrH8)uI*C`$K0O!X*|A0{Yz*^$Nr7n2&Rg(PlrEwNQ zCWo&O&daZlGtM{no3h|5X`vaY=Rr~%R$yPnq!1ISdFwh^Q0*e8@Kb*-l;tw&P?+=uQ{$PdrfT^*b zKRk*0Lj=ffvHSjT7}j;&Gmv}!5Om1=gyp5cA3VVKhnW!Y-t9>A{6Q2Q*Y}6Wb<)?7 z2>n5He18aMOk-7#_yd_5csu4^P)Px#Fi=cXMF6nqSSVP4K!~tdun-Us*jR{=Fi7ZturNr7kkH^*n83)WIOynD`1tsc zkdVlzIBZoE1^@s7xk*GpR9J=Wm5pwLFbss3A3KQ?`u>kQpA#r*VI3e%n#5JKBJF*4 z?BITV-MV$_FXWuNX7?e)3;v+~;7=2}|1!Xz-h&Gk|9l1=aAgN%_S1e&i7wbXK%N$mr`x5=}n@;0E=ClcEJEg37Ly10RE5*06-k50}3ZS zfnW(F5kV5qe*E~9_rk9e5L+O;$8Hba?-Cfl7u$h|cCeY>mb4!Lz#ewz1h=XgqX8b$ z&nEz-h|V5T>8y9vIWXB3P z-tkX~?fk9?wYFZ7H0(xTuRM7Nj0}lp!id;=(r<7P`yB#As}u%N0nVg*s@41+h>blw z$^^trsHqsijoB8JK*TW`;eFEaW5SE|H@u`!N^(97fW=pzA>RCvXevekLZprcrYM5h z=-}sJj2ojalGblXJqkcTtx41(iY35qBk+n4dlM)weh_f42p!M*{Ct?Pu?sz#0bRE2 zxANZMy!cm}|D`n6CI2e}#XIu{H%fv-^Qn5DIp^)SZr%Dn`Ua6A8ihqlowWb}002ov JPDHLkV1h8r|H%LV diff --git a/graphics/pokemon/comfey/anim_front.png b/graphics/pokemon/comfey/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..a76dd3b51e63f8786a7c4af0f5ab0a90f8107c24 GIT binary patch literal 976 zcmV;>126oEP)K?sQRYqVe) zPZto{A_6=Phhr`Qh@M1LRlT!}@$5JU6Uw?skC5;B)XjJ4RS7{DE-Q*_1mcOnpO5Du zlAJ85R)?vkOxPv;_bUR8CbFp$L%3u1~#juSBG)|W4UndW>W7>j;^&`lK+YfBD>T(e7 zndc$l@-a8(Fj7F?I>a_j_jJ+##v*pls&gI z$Z|!_Qxi1pgZa}ItZ15cRWM|p=~*-7L@4Rh1me+gAS<;}p;EHh9ceFPzhmVR=?<6AjJ_kmH|c<%@%%PD#S zi%<2+rSDLEvMkXXg2l6XWl3zMFrHo92gG4nKHnn2^m6j5lL24nOb$=Owu0hbW-~zaV-DPHcV{weY~j57uAuk{^!9 z4Y={(DV~1b=7%RR1U>j6Jxlmu+v0~A2)+2>SRNsGu$f-QTi*P@=6!@f)VJxv(sN4yy!r%pSO4b0000c%es literal 0 HcmV?d00001 diff --git a/graphics/pokemon/comfey/front.png b/graphics/pokemon/comfey/front.png deleted file mode 100644 index d2e87096516a2fbf4cbe36ad505b695133ec0478..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 790 zcmV+x1L^#UP)Px#1ZP1_K>z@;j|==^1poj5Fi=cXMVQc_D0mpS;8=*TKoAfRusAsQ;6Q+YfZ(VY zxVX6RurT=e_}EB@fFK~?SXl6gu=*EHV*mgE32;bRa{vGi!vFvd!vV){sAK>D0&ht~ zK~zY`?Ub=^8Zj8fjdUneq}(-K=!D@Ppk}Rf3BCeVrB)Gcs6?3(D`SVC3S}kHMXW@` zx-LlVa$5%q)}eGELj+Q*HjJ=!inu8|H6%c515)=qopiF_&)@gX=R5EqMFD+dwQs=i z#!5fDnh<_iT+0hU<7vc*!lfm)p#dW>I&KnJ1O>O@Sk?{<>qb=d3E3O_nC|b0TYT-k zMd?6Kn&?9b_aAF@1qPDkpzmxVt3Ql70<{m4AlRH zjQHI^>vWV3@R>i1!TV{g+m=HH`UBtp8JVubDO)PB?ho>Q|9Uo70I~kU9}K5MoINl7 zOAK!E7f$~7G=pt7?UGc1^SVC+PC4f#DZ`DI_h%2Eay+Sm=;7ptv$oc0Q%b4j>*Rt= z=QP`qIslE39+?BD+>uX=mBD1b|EY`|0caM*7MVuINvs^HAf@}$V7=Xj@-{)QeE#)s zKsom`>oxEDuJ?BvB%=TaUh~+Tr09{O>H?tbc};8d8mxT~K!N;_GhkY_?N_5)P-NCF zFOX{`<@0g|k4CpzksYS1gs6{^vaQkRTQ1GShgo>H0MKyoJLlatPC%4I$lcv z+#(BY0A6yZoAx|*h`|!zveRbF000009 za7bBm000ie000ie0hKEb8vp%afg-WB9bl}I?isMekWd&9{{TPMk_yEgX_xkI;N3Z?9oy$J z7AbE^^*(v;>xNA!D%xFssd;x0SNwS{uxJ4VI~1GHtB=;A6`Y(A%n5Dkh?)OYYwby4U=kG z0)Uy2nm99nkrP#|kVOEBbY~fM85xbpoaYyUESU5LORn{nXajab51 z7bSoy9355pgnNTN2f7|}5&)|33F~DCl@24o!EUk-BX~yUl7O*F^|wY9r>` zdxHbUnz)P7^_)j=8QbeaJm1a&r42fAkl^Rm3EU}yS;XZYIgO(yvhPJ{E{ zDj0@Pxgl|T^TYM4pe+Z&Q`j)iXeXSP1i)T+_Llc2 zxfwZee%24qL*JG35x%$_yt}yiBkRLUaXIK;U&|H_XMe~=ntpBh` zaa$qA3M$eDxY{&QpbZMG!L?!(Si$`|zdj3qM~#|Zk8kKqZCC4NwN?PUpf!W)MpM?u z;(9I^fSw3IlTLt}4-B9}tfh{D)azENGL^SM9Gi*0W%e(M9==TR^$%=tgE0DdM4(~ zAH)P|=z4mEZAbpla&|i>;@s1~%pd%g)qyu7<%1~p2j8+8F||yFggPf2);xcf9F$K4In$ID2>fi$4Ux o#clrZ`*wc_m;SKyhdW+>0fCW(rrY%C6#xJL07*qoM6N<$f_h}1RR910 literal 0 HcmV?d00001 diff --git a/graphics/pokemon/cosmog/front.png b/graphics/pokemon/cosmog/front.png deleted file mode 100644 index c1c2cba84fe43086f9117787ef12e5a7d45f5603..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 616 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 CqyG*7 diff --git a/graphics/pokemon/morelull/anim_front.png b/graphics/pokemon/morelull/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..1f9a8e915df4dcee39e3fb3c5c85c47043c188ae GIT binary patch literal 660 zcmV;F0&D$=P)EsEByT(3qI0V5pG55L;Uf00009 za7bBm000ie000ie0hKEb8vpz5 zZwJm*o7<7&p+HF;OjzXjUeMbP80~62XgSKev9|+E*e78tJoa4-VCGOybok>E>)B|g zXL>Znen|ipdZCjky1+gq$vlbg(Vm$)%iuqN(IlCT^b`likID4gZvr^U16p^<;+OuJ z^OAGoC5;E@?`#}k%{Y#SL=S&xB*>nzh#JUpn**3@dcqv1w}L>z@$&0xy+&8ebZHxD zNZeDvvm#y5ueqU$6e;rN+1VrO(!NzEds>q~AV`M+KcFS&BB+qS%K@(kvIW_p0Iw#M z4}gsT=Y0i%BR(U5>?_bDzjK7x0c&5jc}*$V#Q>)Y3RDA4K@5c%O~Hq}Ccj_+GeR*0 zjXK6A;IlYr2_e)e3SPx#1ZP1_K>z@;j|==^1poj5Fi=cXMVQc_;CP65IC$`|$Pf?^m~gOYfT*yLz{uF( zU|>kdxTyH>(5Q%b$k3RWs9>m&zz|zo4FCWD32;bRa{vGi!vFvd!vV){sAK>D0aHmt zK~zY`?b0!8!ax)U@P~*H=+u4z8(kdR)cpttMWtP8NJf{2&eG%dQcFe$p(H`4F6JDw z=s7yItBaIuo&5}roqaDwSO4q(clYj&gHsO7`6b<#F0QI1s9DxExq(#x@(nDjdIZ=_ z_y@Qtm_UQ3Ljb>5Yr68G*+u$F@FH9(g+l--DDbocLOLWc^AI55X2Uj3zlQ*4;PDpc ze(;6>*A-oZRRSEye%)aCq}To6QT9z1*&Yf?vN46o7GB`*2jzY}8MbZd4cLAFoOQx> zcq?2CfHBfj9lk$fJ;ZZ8*KtaKrCw^4q7&dusf9{bXb*0eGqwEEA2|3saP`xjU1tEYgs%Mq^D?|ys&SWe>A)lW|Vuivd#OF;hJ`pwe& zEc^cLqJu0G-!21118Nay0L+q$0>Fb^a^PXnMM3YuTz2t(55L29e|yPA@$3Hj;J3Tm zKQ1}g?H>-u?an;TyC^>H{KMmMdv7kd$jv<eRj$ zXg?58a5eH!L9kdEC7k3kluf8i1xm(1GRQzcZ7e<~ zq70#G0sn*(4A_8Hf^o9qGRXvhX{h_8BS2#!fdPYnOF%_?lH+S9Ljov<3l=u`Hv&}6 zKv}`V5tqRLIjh`?ljs29;edeE7OV%_65jR_V=9T=670_3dhBXhL)jRG+ZF+xfK9dA zqvPFvQz6h2z#;M)V+2}&-|lfQcGMT8M?fV&Q5~>G<}2Vw1$cM>%c70ab(TB?@^F1@ z=~Hukz+%xNRER)Gz|9e}5yD+#XE%nLI|5is`W@wL`O(jj_9i)Cpy6kodGmK%P>6;xl<(vE_6#;c(-`tFX;#4 zO{)#KGyTv3t@b#Q?q&o=y~07iC@@M~*G2t6!7cvel77HGCH-JCRiS<`=lTIJb5aP_ zxwk#c7uM%%8>K}0XW>zkEz|DA9y0s^tV*Rn;1sgK|kk$24D)X zemDhs{eTL@c$OE_5d9+ZkdFP-!=N8>pR_^S#f&rB{h5HWo82vMMaDOY8T3O|_0wMm zUU&W%#_aV&mg|2y{m^RO&C2t1Px=8fN*+ATZ>0qFmLK#31&lcu&h3u;PxV6t?mD62 o&-4Qxx~YEfXZpdZ|DhlL1$ygZaQL-8m;e9(07*qoM6N<$g3r@V-T(jq literal 0 HcmV?d00001 diff --git a/graphics/pokemon/palossand/front.png b/graphics/pokemon/palossand/front.png deleted file mode 100644 index d22845d345aa6449b55cb9d403421e5b20abf2c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 884 zcmV-)1B?8LP)Px#1ZP1_K>z@;j|==^1poj5Fi=cXMVQc_Z~y=h5D?fH82DI7a6lmVxM;|LK=|0; z=%~P;*!Xa;;Q09X00000000000FRDy!vFvP32;bRa{vGi!vFvd!vV){sAK>D0?kQ8 zK~zY`g_N;w+b|G@6#+ul7U=^RL?ta9+PW_g#1BviAlV_40UZrzBS2n(^Z}|D5ReyW zfq3iSC3CkvRPRX2vJ+W38?a1$`g!;BPTBLg5ZQcOt=`PuzgVu8uL0NdJ1kc>A726H zlek)bc?I}%vs%mn`McHUY&PCsFXjR9b{;4c$XP%Em^q08z=NF=@GvV;@O?1nCBF6W z8#ev@If>$DzuoywcmL;{K-WL+_M6T;O-mHtJOB8!-#nNz61jN*0?dQK=`_hCxO?I< z(0!c(Dt0LZ;#3j^q%Z_b9Z2B^0#MsY1tY!FKwq59GKW?wDM3p094JHrZW*|J0TjxJ z#T=l()Rui}Zw18%1{(T5jIkiVk~5^xa0zRvoE5pKQ3N+~tN<-JBZaGj4W+`$R3PiP zQH?b+&=^bWOq7UK3-l3A1i&Ii3C7h`u&GV}7{%RJI|ei*f&nlDxCB&uCOJLsYD@s{ z;n2dGK1YCT0#H`)xTi7#z+#nKgd_$)c-RqOwFT>ek0cy>Nqfqgx&>|L?>%*O-9V{~ zq+^SK#t5vdt|#HHUsnXQ41_K6hW0=%z;Ajwi;nxE^aRKRNcMp|GQWT>CD8By*`kfq zO_mgp6}J19uhe!&W^oY`BfzT+-0dkFA>5WaTN!Td2#}Zj9Ot01q@=00jSAhL+JcO5 zj#t{SaOuIf5P`)2p!ElU2dItBe*`!Pz+wc*IClidQ$WZ0N)xCFs84~D92p2Xj=*UV z1x9!V7^PK4cK9pvnE`j~*x5neKh8SNyS@s|9n7zzmgecko0000< KMNUMnLSTaP)OouA diff --git a/graphics/pokemon/sandygast/anim_front.png b/graphics/pokemon/sandygast/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..bd8e8ed0b6f34dc009e0101d1ca0baa235c1c20f GIT binary patch literal 725 zcmV;`0xJE9P)qcsByf-j5i}K8yh$-SeBzv2%WP`(2CyUz`?Kw>Nhqz}GS0?wd1%pFBB% zMT&)Rt&pftZX62`BSaXsND*L-X3)aVp{n+1vLOpF6-f>6NcFDTkp(>V&lgIw0|5ge zeAErN0m$1qy|Ii3E|(c1nq1%OXH?P@DlM13+4s4zQ(+^l=hs zc*BF#m%u&(egF(n#taM71^^TuMH`TUUi_zXfQ&8JBm{scqPR_BnZbjEoC!(*V6W!$ zUe>qPIlrDztER(T2uhLEgAAC^?QeOxhqJU0tM;=dLegMm=iR9#_+^0rDEsFp3DJ2c zCrz3(>HpDG7rlQ_7eW7Y)*{)MvW_>{;7=mi=Slo4S>qSI9~D8>CDhpY`) z3;rF}{Q;8rL{xP-0F1)Z>24dqxjYh0l2YXvAyZz--)OeipNq?r_b)1W#!lvI6-A0X`wFGcGL1$SC;nm-I~t*X64jlmvT<(l6&C`j>J=Q zOBza^G-lmp+Q65xE~o5(azcB}oG4*49kmu~b;$-}h8c@^rxb~DE#+8x*z5UzMmq+{ zhW!RS0gb*6d8Y#JG|qY~$COfVLr86$8*@UGJuP_`~|7*|k_V9E3oq_9j9S+d+ z+h`+VB%qZ4@9AvaKN{g#(^PbwiW8r`e!EIN<+clB&aT($np^$!e$}gzopr04`9@B>(^b diff --git a/graphics/pokemon/shiinotic/anim_front.png b/graphics/pokemon/shiinotic/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..a9cee08c39bbc7ebfab4bb8cc20e98a63b9d2b93 GIT binary patch literal 1230 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 literal 0 HcmV?d00001 diff --git a/graphics/pokemon/steenee/front.png b/graphics/pokemon/steenee/front.png deleted file mode 100644 index 77ae6e0f22c86bb96d0b43f1df8d6099fc1b2a32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 651 zcmV;60(AX}P)Px#1ZP1_K>z@;j|==^1poj5Fi=cXMF6nqIA}nC$Z%kgP!JFh@aQP``1n|0U|-fG|J+000000B`Ga(f|Me32;bRa{vGi!vFvd!vV){sAK>D0pv+U zK~zY`<&-~*+b|f$We}v}$qsamoG)OP+l?!7V0R1o00-f9<6ANuaV}GbP?~m68g4zD zBDl?zr0(3I+}QE@UHV!sh2&%zy557ZLC??cAITDVj$&tK-{P*BuzcP#hY*|xW+H3@ zXe(f~Zd@!THnma?VG7SXnjD zdm3QqyEVYLE(8Lu*H!5+xh{n5zVg`1OU4+CeJ#K}#^$RW($61lO%B{={CK|p3Rjc& zueAUMV2c9+x4Eu}8n~FOVX~g-ima0% diff --git a/graphics/pokemon/tsareena/anim_front.png b/graphics/pokemon/tsareena/anim_front.png new file mode 100644 index 0000000000000000000000000000000000000000..a3503731e1e72691501281c51489489d69b74322 GIT binary patch literal 1254 zcmVLF8p+W8ap_=NgWl)&o@LqZQ@n~Wk^vbz0(3p^EJ}cU1n9QCo7Z(|0tVs2Yk~j^e$%=O4gF|& zZL`t32`Iz|Xs&0^gi3i07WI_&D(3s0WG3CQh;>|8^tW8x4!H#pdkTNXj+dc zt#ZJT1MZ_XrBA;23*>;}yM0XQV}!sN%7Mxux<#{D0!}#rK-uDN%OC7JdkFwMC}z>I z-*CzRIVtcdSw8-$o&r>w-yi>sHs47E{;s`oTqH{cNC29amMs;bT?hH4^qW<$R4Tph z;(C2k4yg zU>^zsFdDN77+_)+9|L;^O#Z7f{5E7Yuz3wQ74~vX6pXS+!GS7(D=P3a_rtgj#-1Sn zRwD$Ar{X;!pt9YW0R|l0#v2>}AB>7K3mBENYrq)#aK>8zSD66(6tPw{tbtK>dBzE# zh-+_DT(yQYwCJEe*wB)#=c=r`gONnzpeQrP@X@Hs*d{rySAI2-m zAK2W^iDQyKWX9t-!5=1mkl+t|{PPS+{ty{RvOk0sQv5-T|1^IH$A5}HDC&$q$bi<v#Bse|9MK2W1qxLywPtnI3RpApBq;2Qr6TK_)<~M&^=fK~LN;J*i+6 zTm}T3I0;Ur{@`AAPPjlYOePp?y8pAqf$hNS_;P=6YuH{tiN&XN5 z!~mH;4B4su8ea9Vmf{chF!B~P?hktse;5jXAP7C2;}1d)Ua~)E|3`oL7r$A7S*;$b Q-v9sr07*qoM6N<$f-r$VIsgCw literal 0 HcmV?d00001 diff --git a/graphics/pokemon/tsareena/front.png b/graphics/pokemon/tsareena/front.png deleted file mode 100644 index 9072ce8651bf8d7a3ad55bd90beb69972fcd013d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 849 zcmV-X1FrmuP)y*|~)D z8xLbqH{Y`ZK|!#dL{^Xth6fMQ2gU!PNKd=$GFV}LU(%oJYdz?fCV9N?r{C{4NvWdz z?;u3JAJM|=xf{luG@r2I!NR<2+x1`2AF(a*?_Y4A+xYjuABu5qX5q0i}zRkbowT)$AF?Tc6ojwF+gX6P^gi#iOzmTF3dlKcYoExg)jfuO@hbp8fTunLv*Q1=_VBHyU`{()@D>nDCy z(ycOm(&=2(hV2=>sMz#-BT(xxUxifDp3jh@KTx%5IMjz;H3N0}LxXJ*uaf_J` zVnz(~tcw+gfD$}=J?E-RBt~W_cBh*G*ct(CS9QspM+(@T!Ek|~N8qVP7>S9c5N@wP zw*-0wuRTJAWsD8-ib_L|Jt%$#wFjc>SpbG=k3qti7n__{6mLuMVpH-0sQ(NUHVvrL blJfWic7VlxD;2dm00000NkvXXu0mjfp<9A# diff --git a/src/data/graphics/pokemon.h b/src/data/graphics/pokemon.h index 70b60eaa93..5d354b3ee9 100644 --- a/src/data/graphics/pokemon.h +++ b/src/data/graphics/pokemon.h @@ -22017,7 +22017,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_DEWPIDER #if P_FAMILY_FOMANTIS - const u32 gMonFrontPic_Fomantis[] = INCGFX_U32("graphics/pokemon/fomantis/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Fomantis[] = INCGFX_U32("graphics/pokemon/fomantis/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Fomantis[] = INCGFX_U16("graphics/pokemon/fomantis/normal.pal", ".gbapal"); const u32 gMonBackPic_Fomantis[] = INCGFX_U32("graphics/pokemon/fomantis/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Fomantis[] = INCGFX_U16("graphics/pokemon/fomantis/shiny.pal", ".gbapal"); @@ -22051,7 +22051,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_FOMANTIS #if P_FAMILY_MORELULL - const u32 gMonFrontPic_Morelull[] = INCGFX_U32("graphics/pokemon/morelull/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Morelull[] = INCGFX_U32("graphics/pokemon/morelull/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Morelull[] = INCGFX_U16("graphics/pokemon/morelull/normal.pal", ".gbapal"); const u32 gMonBackPic_Morelull[] = INCGFX_U32("graphics/pokemon/morelull/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Morelull[] = INCGFX_U16("graphics/pokemon/morelull/shiny.pal", ".gbapal"); @@ -22067,7 +22067,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS - const u32 gMonFrontPic_Shiinotic[] = INCGFX_U32("graphics/pokemon/shiinotic/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Shiinotic[] = INCGFX_U32("graphics/pokemon/shiinotic/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Shiinotic[] = INCGFX_U16("graphics/pokemon/shiinotic/normal.pal", ".gbapal"); const u32 gMonBackPic_Shiinotic[] = INCGFX_U32("graphics/pokemon/shiinotic/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Shiinotic[] = INCGFX_U16("graphics/pokemon/shiinotic/shiny.pal", ".gbapal"); @@ -22153,7 +22153,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_STUFFUL #if P_FAMILY_BOUNSWEET - const u32 gMonFrontPic_Bounsweet[] = INCGFX_U32("graphics/pokemon/bounsweet/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Bounsweet[] = INCGFX_U32("graphics/pokemon/bounsweet/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Bounsweet[] = INCGFX_U16("graphics/pokemon/bounsweet/normal.pal", ".gbapal"); const u32 gMonBackPic_Bounsweet[] = INCGFX_U32("graphics/pokemon/bounsweet/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Bounsweet[] = INCGFX_U16("graphics/pokemon/bounsweet/shiny.pal", ".gbapal"); @@ -22169,7 +22169,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS - const u32 gMonFrontPic_Steenee[] = INCGFX_U32("graphics/pokemon/steenee/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Steenee[] = INCGFX_U32("graphics/pokemon/steenee/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Steenee[] = INCGFX_U16("graphics/pokemon/steenee/normal.pal", ".gbapal"); const u32 gMonBackPic_Steenee[] = INCGFX_U32("graphics/pokemon/steenee/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Steenee[] = INCGFX_U16("graphics/pokemon/steenee/shiny.pal", ".gbapal"); @@ -22185,7 +22185,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS - const u32 gMonFrontPic_Tsareena[] = INCGFX_U32("graphics/pokemon/tsareena/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Tsareena[] = INCGFX_U32("graphics/pokemon/tsareena/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Tsareena[] = INCGFX_U16("graphics/pokemon/tsareena/normal.pal", ".gbapal"); const u32 gMonBackPic_Tsareena[] = INCGFX_U32("graphics/pokemon/tsareena/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Tsareena[] = INCGFX_U16("graphics/pokemon/tsareena/shiny.pal", ".gbapal"); @@ -22203,7 +22203,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_BOUNSWEET #if P_FAMILY_COMFEY - const u32 gMonFrontPic_Comfey[] = INCGFX_U32("graphics/pokemon/comfey/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Comfey[] = INCGFX_U32("graphics/pokemon/comfey/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Comfey[] = INCGFX_U16("graphics/pokemon/comfey/normal.pal", ".gbapal"); const u32 gMonBackPic_Comfey[] = INCGFX_U32("graphics/pokemon/comfey/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Comfey[] = INCGFX_U16("graphics/pokemon/comfey/shiny.pal", ".gbapal"); @@ -22306,7 +22306,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_WIMPOD #if P_FAMILY_SANDYGAST - const u32 gMonFrontPic_Sandygast[] = INCGFX_U32("graphics/pokemon/sandygast/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Sandygast[] = INCGFX_U32("graphics/pokemon/sandygast/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Sandygast[] = INCGFX_U16("graphics/pokemon/sandygast/normal.pal", ".gbapal"); const u32 gMonBackPic_Sandygast[] = INCGFX_U32("graphics/pokemon/sandygast/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Sandygast[] = INCGFX_U16("graphics/pokemon/sandygast/shiny.pal", ".gbapal"); @@ -22322,7 +22322,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS - const u32 gMonFrontPic_Palossand[] = INCGFX_U32("graphics/pokemon/palossand/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Palossand[] = INCGFX_U32("graphics/pokemon/palossand/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Palossand[] = INCGFX_U16("graphics/pokemon/palossand/normal.pal", ".gbapal"); const u32 gMonBackPic_Palossand[] = INCGFX_U32("graphics/pokemon/palossand/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Palossand[] = INCGFX_U16("graphics/pokemon/palossand/shiny.pal", ".gbapal"); @@ -22488,7 +22488,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_MINIOR #if P_FAMILY_KOMALA - const u32 gMonFrontPic_Komala[] = INCGFX_U32("graphics/pokemon/komala/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Komala[] = INCGFX_U32("graphics/pokemon/komala/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Komala[] = INCGFX_U16("graphics/pokemon/komala/normal.pal", ".gbapal"); const u32 gMonBackPic_Komala[] = INCGFX_U32("graphics/pokemon/komala/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Komala[] = INCGFX_U16("graphics/pokemon/komala/shiny.pal", ".gbapal"); @@ -22573,7 +22573,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_MIMIKYU #if P_FAMILY_BRUXISH - const u32 gMonFrontPic_Bruxish[] = INCGFX_U32("graphics/pokemon/bruxish/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Bruxish[] = INCGFX_U32("graphics/pokemon/bruxish/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Bruxish[] = INCGFX_U16("graphics/pokemon/bruxish/normal.pal", ".gbapal"); const u32 gMonBackPic_Bruxish[] = INCGFX_U32("graphics/pokemon/bruxish/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Bruxish[] = INCGFX_U16("graphics/pokemon/bruxish/shiny.pal", ".gbapal"); @@ -22624,7 +22624,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_DRAMPA #if P_FAMILY_DHELMISE - const u32 gMonFrontPic_Dhelmise[] = INCGFX_U32("graphics/pokemon/dhelmise/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Dhelmise[] = INCGFX_U32("graphics/pokemon/dhelmise/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Dhelmise[] = INCGFX_U16("graphics/pokemon/dhelmise/normal.pal", ".gbapal"); const u32 gMonBackPic_Dhelmise[] = INCGFX_U32("graphics/pokemon/dhelmise/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Dhelmise[] = INCGFX_U16("graphics/pokemon/dhelmise/shiny.pal", ".gbapal"); @@ -22764,7 +22764,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_TAPU_FINI #if P_FAMILY_COSMOG - const u32 gMonFrontPic_Cosmog[] = INCGFX_U32("graphics/pokemon/cosmog/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Cosmog[] = INCGFX_U32("graphics/pokemon/cosmog/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Cosmog[] = INCGFX_U16("graphics/pokemon/cosmog/normal.pal", ".gbapal"); const u32 gMonBackPic_Cosmog[] = INCGFX_U32("graphics/pokemon/cosmog/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Cosmog[] = INCGFX_U16("graphics/pokemon/cosmog/shiny.pal", ".gbapal"); diff --git a/src/data/pokemon/species_info/gen_7_families.h b/src/data/pokemon/species_info/gen_7_families.h index 1558e80f80..5ff7bdb6ac 100644 --- a/src/data/pokemon/species_info/gen_7_families.h +++ b/src/data/pokemon/species_info/gen_7_families.h @@ -3029,8 +3029,15 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Fomantis, .frontPicSize = MON_COORDS_SIZE(40, 48), .frontPicYOffset = 11, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE_SLOW, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 15), + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 25), + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_TIP_MOVE_FORWARD, .backPic = gMonBackPic_Fomantis, .backPicSize = MON_COORDS_SIZE(40, 56), .backPicYOffset = 5, @@ -3227,8 +3234,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Morelull, .frontPicSize = MON_COORDS_SIZE(24, 48), .frontPicYOffset = 10, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_SHAKE_FLASH_YELLOW, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 55), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_GLOW_YELLOW, .backPic = gMonBackPic_Morelull, .backPicSize = MON_COORDS_SIZE(40, 48), .backPicYOffset = 9, @@ -3294,7 +3304,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Shiinotic, .frontPicSize = MON_COORDS_SIZE(56, 56), .frontPicYOffset = 4, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 55), + ANIMCMD_FRAME(1, 55), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_SHAKE_GLOW_WHITE_SLOW, .backPic = gMonBackPic_Shiinotic, .backPicSize = MON_COORDS_SIZE(64, 48), @@ -3695,7 +3709,10 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Bounsweet, .frontPicSize = MON_COORDS_SIZE(32, 40), .frontPicYOffset = 16, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, .backPic = gMonBackPic_Bounsweet, .backPicSize = MON_COORDS_SIZE(48, 40), @@ -3762,8 +3779,13 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Steenee, .frontPicSize = MON_COORDS_SIZE(48, 56), .frontPicYOffset = 7, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 15), + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_V_JUMPS_BIG, .backPic = gMonBackPic_Steenee, .backPicSize = MON_COORDS_SIZE(56, 56), .backPicYOffset = 8, @@ -3828,8 +3850,13 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Tsareena, .frontPicSize = MON_COORDS_SIZE(56, 64), .frontPicYOffset = 1, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_SHRINK_GROW, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 40), + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_V_STRETCH, .backPic = gMonBackPic_Tsareena, .backPicSize = MON_COORDS_SIZE(56, 56), .backPicYOffset = 6, @@ -3895,8 +3922,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Comfey, .frontPicSize = MON_COORDS_SIZE(48, 48), .frontPicYOffset = 9, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_H_SLIDE_WOBBLE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_CIRCULAR_STRETCH_TWICE, .enemyMonElevation = 8, .backPic = gMonBackPic_Comfey, .backPicSize = MON_COORDS_SIZE(64, 56), @@ -4300,8 +4330,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Sandygast, .frontPicSize = MON_COORDS_SIZE(48, 48), .frontPicYOffset = 11, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_CIRCULAR_STRETCH_TWICE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 50), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_H_SHAKE, .backPic = gMonBackPic_Sandygast, .backPicSize = MON_COORDS_SIZE(40, 48), .backPicYOffset = 11, @@ -4367,8 +4400,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Palossand, .frontPicSize = MON_COORDS_SIZE(64, 64), .frontPicYOffset = 0, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_H_VIBRATE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 50), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_GROW_VIBRATE, .backPic = gMonBackPic_Palossand, .backPicSize = MON_COORDS_SIZE(64, 64), .backPicYOffset = 2, @@ -4780,7 +4816,10 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Komala, .frontPicSize = MON_COORDS_SIZE(48, 40), .frontPicYOffset = 12, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 60), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_H_DIP, .backPic = gMonBackPic_Komala, .backPicSize = MON_COORDS_SIZE(64, 48), @@ -5286,8 +5325,13 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Bruxish, .frontPicSize = MON_COORDS_SIZE(56, 40), .frontPicYOffset = 15, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_RISING_WOBBLE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 20), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_H_SPRING, .backPic = gMonBackPic_Bruxish, .backPicSize = MON_COORDS_SIZE(64, 48), .backPicYOffset = 14, @@ -5486,7 +5530,16 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Dhelmise, .frontPicSize = MON_COORDS_SIZE(48, 64), .frontPicYOffset = 1, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_SWING_CONVEX, .enemyMonElevation = 2, .backPic = gMonBackPic_Dhelmise, @@ -6117,7 +6170,10 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Cosmog, .frontPicSize = MON_COORDS_SIZE(56, 48), .frontPicYOffset = 10, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_H_JUMPS_V_STRETCH, .enemyMonElevation = 7, .backPic = gMonBackPic_Cosmog, From 08e503fb662818c19cd9c45108af95999b25042a Mon Sep 17 00:00:00 2001 From: GGbond Date: Sun, 7 Jun 2026 03:17:07 +0800 Subject: [PATCH 59/59] Fix Strong Winds interactions with Weather Ball and healing moves (#10132) --- src/battle_script_commands.c | 5 +- src/battle_util.c | 2 +- test/battle/ability/delta_stream.c | 31 ++-- test/battle/ability/desolate_land.c | 8 +- test/battle/ability/primordial_sea.c | 8 +- test/battle/move_effect/roost.c | 6 +- test/battle/move_effect/weather_ball.c | 43 +++++- test/battle/weather/strong_winds.c | 199 +++++++++++++------------ 8 files changed, 175 insertions(+), 127 deletions(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b4b9b832f1..c2c4b3f17e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -8658,6 +8658,7 @@ static void Cmd_recoverbasedonsunlight(void) s32 recoverAmount = 0; u32 weather = GetWeather(); u32 attackerWeather = GetAttackerWeather(GetBattlerHoldEffect(gBattlerAttacker), GetBattlerAbility(gBattlerAttacker), weather); + u32 healingWeather = attackerWeather & ~B_WEATHER_STRONG_WINDS; if (GetMoveEffect(gCurrentMove) == EFFECT_SHORE_UP) { if (attackerWeather & B_WEATHER_SANDSTORM) @@ -8669,7 +8670,7 @@ static void Cmd_recoverbasedonsunlight(void) { if (attackerWeather & B_WEATHER_SUN) recoverAmount = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; - else if (!(GetWeather() & B_WEATHER_ANY) || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) + else if (!(healingWeather & B_WEATHER_ANY) || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; else // not sunny weather recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; @@ -8700,7 +8701,7 @@ static void Cmd_recoverbasedonsunlight(void) } if (attackerWeather & B_WEATHER_SUN) recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 2; - else if (!(attackerWeather & B_WEATHER_ANY) || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) + else if (!(healingWeather & B_WEATHER_ANY) || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 4; else // not sunny weather recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 8; diff --git a/src/battle_util.c b/src/battle_util.c index 62df8743d9..b90590ed4d 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6182,7 +6182,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) basePower *= 2; break; case EFFECT_WEATHER_BALL: - if (GetAttackerWeather(ctx->holdEffects[ctx->battlerAtk], ctx->abilities[ctx->battlerAtk], ctx->weather) & B_WEATHER_ANY) + if (GetAttackerWeather(ctx->holdEffects[ctx->battlerAtk], ctx->abilities[ctx->battlerAtk], ctx->weather) & (B_WEATHER_ANY & ~B_WEATHER_STRONG_WINDS)) basePower *= 2; break; case EFFECT_PURSUIT: diff --git a/test/battle/ability/delta_stream.c b/test/battle/ability/delta_stream.c index 0ea7429ff4..816317459a 100644 --- a/test/battle/ability/delta_stream.c +++ b/test/battle/ability/delta_stream.c @@ -8,18 +8,18 @@ DOUBLE_BATTLE_TEST("Delta Stream doesn't activate if there's already strong winds") { GIVEN { + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { SWITCH(playerLeft, 2); } + TURN { + MOVE(opponentLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); + MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); + } } SCENE { ABILITY_POPUP(opponentLeft, ABILITY_DELTA_STREAM); MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); - SWITCH_OUT_MESSAGE("Wobbuffet"); - SEND_IN_MESSAGE("Rayquaza"); NONE_OF { ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); @@ -30,18 +30,21 @@ DOUBLE_BATTLE_TEST("Delta Stream doesn't activate if there's already strong wind DOUBLE_BATTLE_TEST("Strong winds continue as long as there's a Pokémon with Delta Stream on the field") { GIVEN { - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); HP(1); } - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } - OPPONENT(SPECIES_WOBBUFFET); + PLAYER(SPECIES_RAYQUAZA) { HP(1); Speed(5); Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); } + PLAYER(SPECIES_WOBBUFFET) { Speed(3); } + OPPONENT(SPECIES_RAYQUAZA) { Speed(2); Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, MOVE_SCRATCH); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(1); } } WHEN { + TURN { + MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); + MOVE(opponentLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); + } TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerLeft); SEND_OUT(playerLeft, 2); } } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft); - HP_BAR(playerLeft, hp: 0); - MESSAGE("Rayquaza fainted!"); - SEND_IN_MESSAGE("Wobbuffet"); + HP_BAR(playerLeft); NOT MESSAGE("The mysterious strong winds have dissipated!"); } THEN { EXPECT(gBattleWeather & B_WEATHER_STRONG_WINDS); diff --git a/test/battle/ability/desolate_land.c b/test/battle/ability/desolate_land.c index e45197aea4..6a35847b1a 100644 --- a/test/battle/ability/desolate_land.c +++ b/test/battle/ability/desolate_land.c @@ -128,7 +128,8 @@ SINGLE_BATTLE_TEST("Desolate Land blocks weather-setting moves") SINGLE_BATTLE_TEST("Desolate Land prevents other weather abilities") { - enum Ability ability; u16 species; + enum Ability ability; + enum Species species; PARAMETRIZE { ability = ABILITY_DROUGHT; species = SPECIES_NINETALES; } PARAMETRIZE { ability = ABILITY_DRIZZLE; species = SPECIES_POLITOED; } PARAMETRIZE { ability = ABILITY_SAND_STREAM; species = SPECIES_HIPPOWDON; } @@ -151,10 +152,9 @@ SINGLE_BATTLE_TEST("Desolate Land can be replaced by Delta Stream") { GIVEN { PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } } WHEN { - TURN { SWITCH(opponent, 1); } + TURN { MOVE(opponent, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } } SCENE { ABILITY_POPUP(opponent, ABILITY_DELTA_STREAM); MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); diff --git a/test/battle/ability/primordial_sea.c b/test/battle/ability/primordial_sea.c index b6000718cc..9cd37096dc 100644 --- a/test/battle/ability/primordial_sea.c +++ b/test/battle/ability/primordial_sea.c @@ -94,7 +94,8 @@ SINGLE_BATTLE_TEST("Primordial Sea blocks weather-setting moves") SINGLE_BATTLE_TEST("Primordial Sea prevents other weather abilities") { - enum Ability ability; u16 species; + enum Ability ability; + enum Species species; PARAMETRIZE { ability = ABILITY_DROUGHT; species = SPECIES_NINETALES; } PARAMETRIZE { ability = ABILITY_DRIZZLE; species = SPECIES_POLITOED; } PARAMETRIZE { ability = ABILITY_SAND_STREAM; species = SPECIES_HIPPOWDON; } @@ -117,10 +118,9 @@ SINGLE_BATTLE_TEST("Primordial Sea can be replaced by Delta Stream") { GIVEN { PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } } WHEN { - TURN { SWITCH(opponent, 1); } + TURN { MOVE(opponent, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } } SCENE { ABILITY_POPUP(opponent, ABILITY_DELTA_STREAM); MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); diff --git a/test/battle/move_effect/roost.c b/test/battle/move_effect/roost.c index f42ebad3ca..a1e674ac50 100644 --- a/test/battle/move_effect/roost.c +++ b/test/battle/move_effect/roost.c @@ -255,12 +255,14 @@ DOUBLE_BATTLE_TEST("Roost suppresses the user's not-yet-aquired Flying-type this SINGLE_BATTLE_TEST("Roost prevents a Flying-type user from being protected by Delta Stream") { GIVEN { - ASSUME(GetSpeciesType(SPECIES_RAYQUAZA, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { HP(1); Ability(ABILITY_DELTA_STREAM); } + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 1) == TYPE_FLYING); + PLAYER(SPECIES_RAYQUAZA) { HP(1); Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, MOVE_ROOST); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_ICE_BEAM); } } SCENE { + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); MESSAGE("Rayquaza used Roost!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player); MESSAGE("Rayquaza's HP was restored."); diff --git a/test/battle/move_effect/weather_ball.c b/test/battle/move_effect/weather_ball.c index 1ce90eec65..70cd269f4f 100644 --- a/test/battle/move_effect/weather_ball.c +++ b/test/battle/move_effect/weather_ball.c @@ -97,10 +97,49 @@ SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to an Ice-type move } } +DOUBLE_BATTLE_TEST("Weather Ball doesn't double its power and stays a Normal-type move in strong winds", s16 damage) +{ + bool32 strongWinds; + enum Species species; + PARAMETRIZE { strongWinds = FALSE; species = SPECIES_WOBBUFFET; } + PARAMETRIZE { strongWinds = TRUE; species = SPECIES_WOBBUFFET; } + PARAMETRIZE { strongWinds = TRUE; species = SPECIES_GASTLY; } + + GIVEN { + ASSUME(GetMoveType(MOVE_WEATHER_BALL) == TYPE_NORMAL); + ASSUME(GetSpeciesType(SPECIES_GASTLY, 0) == TYPE_GHOST); + if (strongWinds) + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } + else + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_AIR_LOCK); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(species); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (strongWinds) + TURN { MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } + TURN { MOVE(playerRight, MOVE_WEATHER_BALL, target: opponentLeft); } + } SCENE { + if (strongWinds) + ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); + if (species == SPECIES_GASTLY) { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WEATHER_BALL, playerRight); + HP_BAR(opponentLeft); + } + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WEATHER_BALL, playerRight); + HP_BAR(opponentLeft, captureDamage: &results[i].damage); + } + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + SINGLE_BATTLE_TEST("Weather Ball doesn't double its power in Sunlight or Rain if Cloud Nine/Air Lock is on the field", s16 damage) { enum Move setupMove; - u16 species; + enum Species species; enum Ability ability; PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; setupMove = MOVE_CELEBRATE; } @@ -131,7 +170,7 @@ SINGLE_BATTLE_TEST("Weather Ball doesn't double its power in Sunlight or Rain if SINGLE_BATTLE_TEST("Weather Ball doesn't change type in Sunlight or Rain if Cloud Nine/Air Lock is on the field") { enum Move setupMove; - u16 species; + enum Species species; enum Ability ability; PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; setupMove = MOVE_SUNNY_DAY; } diff --git a/test/battle/weather/strong_winds.c b/test/battle/weather/strong_winds.c index 9ce12fdf92..d583bfc915 100644 --- a/test/battle/weather/strong_winds.c +++ b/test/battle/weather/strong_winds.c @@ -1,97 +1,77 @@ #include "global.h" #include "test/battle.h" -DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers") // Electric, Ice, Rock +ASSUMPTIONS +{ + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_ICE_BEAM) == TYPE_ICE); + ASSUME(GetMoveType(MOVE_ROCK_THROW) == TYPE_ROCK); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_FLYING || GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); +} + +DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers") { enum Move move; - bool32 targetPlayer; - - PARAMETRIZE { move = MOVE_THUNDER_SHOCK; targetPlayer = TRUE; } - PARAMETRIZE { move = MOVE_ICE_BEAM; targetPlayer = TRUE; } - PARAMETRIZE { move = MOVE_ROCK_THROW; targetPlayer = TRUE; } - PARAMETRIZE { move = MOVE_THUNDER_SHOCK; targetPlayer = FALSE; } - PARAMETRIZE { move = MOVE_ICE_BEAM; targetPlayer = FALSE; } - PARAMETRIZE { move = MOVE_ROCK_THROW; targetPlayer = FALSE; } + PARAMETRIZE { move = MOVE_THUNDER_SHOCK; } + PARAMETRIZE { move = MOVE_ICE_BEAM; } + PARAMETRIZE { move = MOVE_ROCK_THROW; } GIVEN { - ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); - ASSUME(GetMoveType(MOVE_ICE_BEAM) == TYPE_ICE); - ASSUME(GetMoveType(MOVE_ROCK_THROW) == TYPE_ROCK); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, move); } PLAYER(SPECIES_PIDGEY); OPPONENT(SPECIES_PIDGEY); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - if (targetPlayer) - TURN { MOVE(opponentLeft, move, target: playerRight); } - else - TURN { MOVE(playerRight, move, target: opponentLeft); } - } SCENE { - if (targetPlayer) { - if (move == MOVE_THUNDER_SHOCK) - MESSAGE("The opposing Pidgey used Thunder Shock!"); - else if (move == MOVE_ICE_BEAM) - MESSAGE("The opposing Pidgey used Ice Beam!"); - else - MESSAGE("The opposing Pidgey used Rock Throw!"); - MESSAGE("The mysterious strong winds weakened the attack!"); - ANIMATION(ANIM_TYPE_MOVE, move, opponentLeft); - } else { - if (move == MOVE_THUNDER_SHOCK) - MESSAGE("Pidgey used Thunder Shock!"); - else if (move == MOVE_ICE_BEAM) - MESSAGE("Pidgey used Ice Beam!"); - else - MESSAGE("Pidgey used Rock Throw!"); - MESSAGE("The mysterious strong winds weakened the attack!"); - ANIMATION(ANIM_TYPE_MOVE, move, playerRight); + TURN { MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } + TURN { + MOVE(playerLeft, move, target: opponentLeft); + MOVE(opponentRight, move, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); + ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); + EFFECTIVENESS_SE(opponentLeft, SE_EFFECTIVE); + HP_BAR(opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); + EFFECTIVENESS_SE(playerRight, SE_EFFECTIVE); + HP_BAR(playerRight); } } -DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers - Inverse Battle", s16 damagePlayer, s16 damageOpponent) // Bug, Fighting, Grass +DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers - Inverse Battle") { enum Move move; - bool32 strongWinds; - - PARAMETRIZE { move = MOVE_BUG_BITE; strongWinds = FALSE; } - PARAMETRIZE { move = MOVE_BUG_BITE; strongWinds = TRUE; } - PARAMETRIZE { move = MOVE_KARATE_CHOP; strongWinds = FALSE; } - PARAMETRIZE { move = MOVE_KARATE_CHOP; strongWinds = TRUE; } - PARAMETRIZE { move = MOVE_VINE_WHIP; strongWinds = FALSE; } - PARAMETRIZE { move = MOVE_VINE_WHIP; strongWinds = TRUE; } + PARAMETRIZE { move = MOVE_BUG_BITE; } + PARAMETRIZE { move = MOVE_KARATE_CHOP; } + PARAMETRIZE { move = MOVE_VINE_WHIP; } + PARAMETRIZE { move = MOVE_MUD_SLAP; } GIVEN { FLAG_SET(B_FLAG_INVERSE_BATTLE); ASSUME(GetMoveType(MOVE_BUG_BITE) == TYPE_BUG); ASSUME(GetMoveType(MOVE_KARATE_CHOP) == TYPE_FIGHTING); ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); + ASSUME(GetMoveType(MOVE_MUD_SLAP) == TYPE_GROUND); ASSUME(GetSpeciesType(SPECIES_TORNADUS, 0) == TYPE_FLYING); ASSUME(GetSpeciesType(SPECIES_TORNADUS, 1) == TYPE_FLYING); - if (strongWinds) - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } - else - PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, move); } PLAYER(SPECIES_TORNADUS); OPPONENT(SPECIES_TORNADUS); OPPONENT(SPECIES_WOBBUFFET); } WHEN { + TURN { MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { - MOVE(opponentLeft, move, target: playerRight); - MOVE(playerRight, move, target: opponentLeft); + MOVE(playerLeft, move, target: opponentLeft); + MOVE(opponentRight, move, target: playerRight); } } SCENE { - HP_BAR(playerRight, captureDamage: &results[i].damagePlayer); - HP_BAR(opponentLeft, captureDamage: &results[i].damageOpponent); - } FINALLY { - EXPECT_GT(results[0].damagePlayer, results[1].damagePlayer); - EXPECT_GT(results[0].damageOpponent, results[1].damageOpponent); - EXPECT_GT(results[2].damagePlayer, results[3].damagePlayer); - EXPECT_GT(results[2].damageOpponent, results[3].damageOpponent); - EXPECT_GT(results[4].damagePlayer, results[5].damagePlayer); - EXPECT_GT(results[4].damageOpponent, results[5].damageOpponent); + ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); + ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); + EFFECTIVENESS_SE(opponentLeft, SE_EFFECTIVE); + HP_BAR(opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); + EFFECTIVENESS_SE(playerRight, SE_EFFECTIVE); + HP_BAR(playerRight); } } @@ -99,16 +79,13 @@ SINGLE_BATTLE_TEST("Strong winds prevent Weakness Policy from activating on Flyi { GIVEN { ASSUME(GetItemHoldEffect(ITEM_WEAKNESS_POLICY) == HOLD_EFFECT_WEAKNESS_POLICY); - ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); Moves(MOVE_THUNDER_SHOCK); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, MOVE_THUNDER_SHOCK); } OPPONENT(SPECIES_PIDGEY) { Item(ITEM_WEAKNESS_POLICY); } } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { MOVE(player, MOVE_THUNDER_SHOCK); } } SCENE { - MESSAGE("Rayquaza used Thunder Shock!"); - MESSAGE("The mysterious strong winds weakened the attack!"); + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_SHOCK, player); HP_BAR(opponent); NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); @@ -118,35 +95,36 @@ SINGLE_BATTLE_TEST("Strong winds prevent Weakness Policy from activating on Flyi SINGLE_BATTLE_TEST("Anticipation still triggers with Strong Winds active") { GIVEN { - ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); Moves(MOVE_THUNDER_SHOCK, MOVE_CELEBRATE); } - OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_CELEBRATE); } + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 0) == TYPE_DRAGON); + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 1) == TYPE_FLYING); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } + OPPONENT(SPECIES_EEVEE) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_ROCK_THROW, MOVE_SKILL_SWAP); } } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); MOVE(opponent, MOVE_SKILL_SWAP); } } SCENE { - ABILITY_POPUP(opponent, ABILITY_ANTICIPATION); - MESSAGE("Rayquaza used Celebrate!"); - MESSAGE("The opposing Pidgey used Celebrate!"); + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); + ABILITY_POPUP(player, ABILITY_ANTICIPATION); } } -SINGLE_BATTLE_TEST("Anticipation still triggers with Strong Winds active in Inverse Battle") +SINGLE_BATTLE_TEST("Anticipation still triggers with Strong Winds active - Inverse Battle") { GIVEN { FLAG_SET(B_FLAG_INVERSE_BATTLE); - ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); - ASSUME(GetSpeciesType(SPECIES_TORNADUS, 0) == TYPE_FLYING); - ASSUME(GetSpeciesType(SPECIES_TORNADUS, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); Moves(MOVE_VINE_WHIP, MOVE_CELEBRATE); } - OPPONENT(SPECIES_TORNADUS) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_CELEBRATE); } + ASSUME(GetMoveType(MOVE_BUG_BITE) == TYPE_BUG); + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 0) == TYPE_DRAGON); + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 1) == TYPE_FLYING); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } + OPPONENT(SPECIES_EEVEE) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_BUG_BITE, MOVE_SKILL_SWAP); } } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); MOVE(opponent, MOVE_SKILL_SWAP); } } SCENE { - ABILITY_POPUP(opponent, ABILITY_ANTICIPATION); - MESSAGE("Rayquaza used Celebrate!"); - MESSAGE("The opposing Tornadus used Celebrate!"); + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); + ABILITY_POPUP(player, ABILITY_ANTICIPATION); } } @@ -154,18 +132,17 @@ SINGLE_BATTLE_TEST("Strong winds don't affect Stealth Rock's damage") { GIVEN { ASSUME(GetMoveEffect(MOVE_STEALTH_ROCK) == EFFECT_STEALTH_ROCK); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_PIDGEY); - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_PIDGEY){ HP(200); MaxHP(200); } + OPPONENT(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, MOVE_STEALTH_ROCK); } } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { MOVE(opponent, MOVE_STEALTH_ROCK); } TURN { SWITCH(player, 1); } } SCENE { - s32 maxHP = GetMonData(&PLAYER_PARTY[1], MON_DATA_MAX_HP); + ABILITY_POPUP(opponent, ABILITY_DELTA_STREAM); ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); - HP_BAR(player, damage: maxHP / 4); + HP_BAR(player, damage: 50); } } @@ -185,11 +162,13 @@ SINGLE_BATTLE_TEST("Strong winds block weather-setting moves") ASSUME(GetMoveWeatherType(MOVE_SANDSTORM) == BATTLE_WEATHER_SANDSTORM); ASSUME(GetMoveWeatherType(MOVE_HAIL) == BATTLE_WEATHER_HAIL); ASSUME(GetMoveWeatherType(MOVE_SNOWSCAPE) == BATTLE_WEATHER_SNOW); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { MOVE(opponent, move); } } SCENE { + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); NOT ANIMATION(ANIM_TYPE_MOVE, move, opponent); } THEN { EXPECT(gBattleWeather & B_WEATHER_STRONG_WINDS); @@ -199,17 +178,18 @@ SINGLE_BATTLE_TEST("Strong winds block weather-setting moves") SINGLE_BATTLE_TEST("Strong winds prevent other weather abilities") { enum Ability ability; - u16 species; + enum Species species; PARAMETRIZE { ability = ABILITY_DROUGHT; species = SPECIES_NINETALES; } PARAMETRIZE { ability = ABILITY_DRIZZLE; species = SPECIES_POLITOED; } PARAMETRIZE { ability = ABILITY_SAND_STREAM; species = SPECIES_HIPPOWDON; } PARAMETRIZE { ability = ABILITY_SNOW_WARNING; species = SPECIES_ABOMASNOW; } GIVEN { - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { SWITCH(opponent, 1); } } SCENE { ABILITY_POPUP(opponent, ability); @@ -221,10 +201,11 @@ SINGLE_BATTLE_TEST("Strong winds prevent other weather abilities") SINGLE_BATTLE_TEST("Strong winds can be replaced by Desolate Land") { GIVEN { - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { SWITCH(opponent, 1); } } SCENE { ABILITY_POPUP(opponent, ABILITY_DESOLATE_LAND); @@ -237,10 +218,11 @@ SINGLE_BATTLE_TEST("Strong winds can be replaced by Desolate Land") SINGLE_BATTLE_TEST("Strong winds can be replaced by Primordial Sea") { GIVEN { - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { SWITCH(opponent, 1); } } SCENE { ABILITY_POPUP(opponent, ABILITY_PRIMORDIAL_SEA); @@ -249,3 +231,24 @@ SINGLE_BATTLE_TEST("Strong winds can be replaced by Primordial Sea") EXPECT(gBattleWeather & B_WEATHER_RAIN_PRIMAL); } } + +SINGLE_BATTLE_TEST("Strong winds don't reduce Synthesis, Morning Sun or Moonlight recovery") +{ + enum Move move; + enum BattleMoveEffects effect; + PARAMETRIZE { move = MOVE_SYNTHESIS; effect = EFFECT_SYNTHESIS; } + PARAMETRIZE { move = MOVE_MORNING_SUN; effect = EFFECT_MORNING_SUN; } + PARAMETRIZE { move = MOVE_MOONLIGHT; effect = EFFECT_MOONLIGHT; } + + GIVEN { + ASSUME(GetMoveEffect(move) == effect); + PLAYER(SPECIES_RAYQUAZA) { HP(1); MaxHP(200); Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, move); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } + TURN { MOVE(player, move); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); + HP_BAR(player, damage: -100); + } +}