From 4618ba740756547e4534d8d29a6e5651cf8bca8e Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Tue, 1 Apr 2025 00:25:30 +0200 Subject: [PATCH 01/19] Align gMPlayTrack_BGM --- sound/music_player_table.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/music_player_table.inc b/sound/music_player_table.inc index 5981a4d037..955d4d556f 100644 --- a/sound/music_player_table.inc +++ b/sound/music_player_table.inc @@ -5,6 +5,7 @@ .equiv NUM_TRACKS_SE3, 1 .bss + .align 2 gMPlayTrack_BGM:: .space TRACK_SIZE * NUM_TRACKS_BGM From a3075325a0ef2e10ad3cc0550d37e30c9c999ef2 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Sat, 5 Apr 2025 21:18:07 -0300 Subject: [PATCH 02/19] GENDER_COUNT in sPlayer/RivalAvatarGfxIds (#2117) --- src/field_player_avatar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c index 1f0708af22..43a7189da2 100644 --- a/src/field_player_avatar.c +++ b/src/field_player_avatar.c @@ -232,7 +232,7 @@ static bool8 (*const sArrowWarpMetatileBehaviorChecks[])(u8) = [DIR_EAST - 1] = MetatileBehavior_IsEastArrowWarp, }; -static const u8 sRivalAvatarGfxIds[][2] = +static const u8 sRivalAvatarGfxIds[][GENDER_COUNT] = { [PLAYER_AVATAR_STATE_NORMAL] = {OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL, OBJ_EVENT_GFX_RIVAL_MAY_NORMAL}, [PLAYER_AVATAR_STATE_MACH_BIKE] = {OBJ_EVENT_GFX_RIVAL_BRENDAN_MACH_BIKE, OBJ_EVENT_GFX_RIVAL_MAY_MACH_BIKE}, @@ -244,7 +244,7 @@ static const u8 sRivalAvatarGfxIds[][2] = [PLAYER_AVATAR_STATE_WATERING] = {OBJ_EVENT_GFX_BRENDAN_WATERING, OBJ_EVENT_GFX_MAY_WATERING} }; -static const u8 sPlayerAvatarGfxIds[][2] = +static const u8 sPlayerAvatarGfxIds[][GENDER_COUNT] = { [PLAYER_AVATAR_STATE_NORMAL] = {OBJ_EVENT_GFX_BRENDAN_NORMAL, OBJ_EVENT_GFX_MAY_NORMAL}, [PLAYER_AVATAR_STATE_MACH_BIKE] = {OBJ_EVENT_GFX_BRENDAN_MACH_BIKE, OBJ_EVENT_GFX_MAY_MACH_BIKE}, From 1672d99060fdb08966230c0b8100d17032d19803 Mon Sep 17 00:00:00 2001 From: cawtds <38510667+cawtds@users.noreply.github.com> Date: Wed, 9 Apr 2025 13:40:39 +0200 Subject: [PATCH 03/19] make linkDirection more robust to member reordering --- include/global.fieldmap.h | 7 +++++-- src/event_object_movement.c | 24 ++++++++++++------------ src/overworld.c | 2 +- src/trainer_see.c | 12 ++++++------ 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/include/global.fieldmap.h b/include/global.fieldmap.h index c7a4133ea8..d3e260e192 100644 --- a/include/global.fieldmap.h +++ b/include/global.fieldmap.h @@ -210,8 +210,11 @@ struct ObjectEvent /*0x14*/ struct Coords16 previousCoords; /*0x18*/ u16 facingDirection:4; // current direction? u16 movementDirection:4; - u16 rangeX:4; - u16 rangeY:4; + struct __attribute__((packed)) + { + u16 rangeX:4; + u16 rangeY:4; + } range; /*0x1A*/ u8 fieldEffectSpriteId; /*0x1B*/ u8 warpArrowSpriteId; /*0x1C*/ u8 movementActionId; diff --git a/src/event_object_movement.c b/src/event_object_movement.c index b3ffb76193..3f8594945e 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -1301,8 +1301,8 @@ static u8 InitObjectEventStateFromTemplate(const struct ObjectEventTemplate *tem objectEvent->previousCoords.y = y; objectEvent->currentElevation = template->elevation; objectEvent->previousElevation = template->elevation; - objectEvent->rangeX = template->movementRangeX; - objectEvent->rangeY = template->movementRangeY; + objectEvent->range.rangeX = template->movementRangeX; + objectEvent->range.rangeY = template->movementRangeY; objectEvent->trainerType = template->trainerType; objectEvent->mapNum = mapNum; objectEvent->trainerRange_berryTreeId = template->trainerRange_berryTreeId; @@ -1311,10 +1311,10 @@ static u8 InitObjectEventStateFromTemplate(const struct ObjectEventTemplate *tem SetObjectEventDynamicGraphicsId(objectEvent); if (sMovementTypeHasRange[objectEvent->movementType]) { - if (objectEvent->rangeX == 0) - objectEvent->rangeX++; - if (objectEvent->rangeY == 0) - objectEvent->rangeY++; + if (objectEvent->range.rangeX == 0) + objectEvent->range.rangeX++; + if (objectEvent->range.rangeY == 0) + objectEvent->range.rangeY++; } return objectEventId; } @@ -4682,18 +4682,18 @@ static bool8 IsCoordOutsideObjectEventMovementRange(struct ObjectEvent *objectEv s16 top; s16 bottom; - if (objectEvent->rangeX != 0) + if (objectEvent->range.rangeX != 0) { - left = objectEvent->initialCoords.x - objectEvent->rangeX; - right = objectEvent->initialCoords.x + objectEvent->rangeX; + left = objectEvent->initialCoords.x - objectEvent->range.rangeX; + right = objectEvent->initialCoords.x + objectEvent->range.rangeX; if (left > x || right < x) return TRUE; } - if (objectEvent->rangeY != 0) + if (objectEvent->range.rangeY != 0) { - top = objectEvent->initialCoords.y - objectEvent->rangeY; - bottom = objectEvent->initialCoords.y + objectEvent->rangeY; + top = objectEvent->initialCoords.y - objectEvent->range.rangeY; + bottom = objectEvent->initialCoords.y + objectEvent->range.rangeY; if (top > y || bottom < y) return TRUE; diff --git a/src/overworld.c b/src/overworld.c index e2c47530be..355c776a26 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -2931,7 +2931,7 @@ static void ZeroObjectEvent(struct ObjectEvent *objEvent) // conflict with the usual Event Object struct, thus the definitions. #define linkGender(obj) obj->singleMovementActive // not even one can reference *byte* aligned bitfield members... -#define linkDirection(obj) ((u8 *)obj)[offsetof(typeof(*obj), fieldEffectSpriteId) - 1] // -> rangeX +#define linkDirection(obj) ((u8 *)obj)[offsetof(typeof(*obj), range)] // -> rangeX static void SpawnLinkPlayerObjectEvent(u8 linkPlayerId, s16 x, s16 y, u8 gender) { diff --git a/src/trainer_see.c b/src/trainer_see.c index 212cbbdec3..059e13ed7d 100644 --- a/src/trainer_see.c +++ b/src/trainer_see.c @@ -389,15 +389,15 @@ static u8 CheckPathBetweenTrainerAndPlayer(struct ObjectEvent *trainerObj, u8 ap return 0; } - rangeX = trainerObj->rangeX; - rangeY = trainerObj->rangeY; - trainerObj->rangeX = 0; - trainerObj->rangeY = 0; + rangeX = trainerObj->range.rangeX; + rangeY = trainerObj->range.rangeY; + trainerObj->range.rangeX = 0; + trainerObj->range.rangeY = 0; collision = GetCollisionAtCoords(trainerObj, x, y, direction); - trainerObj->rangeX = rangeX; - trainerObj->rangeY = rangeY; + trainerObj->range.rangeX = rangeX; + trainerObj->range.rangeY = rangeY; if (collision == COLLISION_OBJECT_EVENT) return approachDistance; From d890436b2ac6fa44afe2aca9c723360e6071d1c4 Mon Sep 17 00:00:00 2001 From: pokemonmasteraaron Date: Wed, 9 Apr 2025 09:06:20 -0400 Subject: [PATCH 04/19] Fixed a compilation error if using AGBPrint as your log handler, misnamed AGBPrintfInit should be AGBPrintInit --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 5750ad2171..29c026624d 100644 --- a/src/main.c +++ b/src/main.c @@ -125,7 +125,7 @@ void AgbMain() #if (LOG_HANDLER == LOG_HANDLER_MGBA_PRINT) (void) MgbaOpen(); #elif (LOG_HANDLER == LOG_HANDLER_AGB_PRINT) - AGBPrintfInit(); + AGBPrintInit(); #endif #endif for (;;) From 89da80b9d1f929e9259e554033f2d75e52cbb093 Mon Sep 17 00:00:00 2001 From: Pawkkie <61265402+Pawkkie@users.noreply.github.com> Date: Wed, 9 Apr 2025 09:37:59 -0400 Subject: [PATCH 05/19] Ability access cleanup for #6550 (#6565) --- src/battle_ai_util.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index a15d8df6c6..c9fe300652 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3132,9 +3132,9 @@ static inline bool32 DoesBattlerBenefitFromAllVolatileStatus(u32 battler, u32 ab bool32 ShouldPoison(u32 battlerAtk, u32 battlerDef) { - u32 defAbility = GetBattlerAbility(battlerDef); + u32 defAbility = AI_DATA->abilities[battlerDef]; // Battler can be poisoned and has move/ability that synergizes with being poisoned - if (CanBePoisoned(battlerAtk, battlerDef, GetBattlerAbility(battlerDef)) && ( + if (CanBePoisoned(battlerAtk, battlerDef, defAbility) && ( DoesBattlerBenefitFromAllVolatileStatus(battlerDef, defAbility) || defAbility == ABILITY_POISON_HEAL || (defAbility == ABILITY_TOXIC_BOOST && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)))) @@ -3152,7 +3152,7 @@ bool32 ShouldPoison(u32 battlerAtk, u32 battlerDef) bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef) { - u32 defAbility = GetBattlerAbility(battlerDef); + u32 defAbility = AI_DATA->abilities[battlerDef]; // Battler can be burned and has move/ability that synergizes with being burned if (CanBeBurned(battlerDef, defAbility) && ( DoesBattlerBenefitFromAllVolatileStatus(battlerDef, defAbility) @@ -3186,7 +3186,7 @@ bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef) } else { - u32 defAbility = GetBattlerAbility(battlerDef); + u32 defAbility = AI_DATA->abilities[battlerDef]; // Battler can be frostbitten and has move/ability that synergizes with being frostbitten if (CanBeFrozen(battlerDef) && DoesBattlerBenefitFromAllVolatileStatus(battlerDef, defAbility)) @@ -3206,7 +3206,7 @@ bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef) bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef) { - u32 defAbility = GetBattlerAbility(battlerDef); + u32 defAbility = AI_DATA->abilities[battlerDef]; // Battler can be paralyzed and has move/ability that synergizes with being paralyzed if (CanBeParalyzed(battlerDef, defAbility) && ( DoesBattlerBenefitFromAllVolatileStatus(battlerDef, defAbility))) From 60a4e191aeb2a3bac36b3bd294ae4aed5fdcc253 Mon Sep 17 00:00:00 2001 From: wiz1989 <80073265+wiz1989@users.noreply.github.com> Date: Thu, 10 Apr 2025 14:56:49 +0200 Subject: [PATCH 06/19] fixed damage calculations in CanTargetFaintAiWithMod() (#6446) Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- src/battle_ai_switch_items.c | 60 ++++++++++++++++++++++++++++++++++-- src/battle_ai_util.c | 2 +- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 242c030838..3f742536fd 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -30,6 +30,7 @@ static bool32 AI_ShouldHeal(u32 battler, u32 healAmount); static bool32 AI_OpponentCanFaintAiWithMod(u32 battler, u32 healAmount); static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon); static bool32 CanAbilityTrapOpponent(u16 ability, u32 opponent); +static u32 GetHPHealAmount(u8 itemEffectParam, struct Pokemon *mon); static void InitializeSwitchinCandidate(struct Pokemon *mon) { @@ -2250,6 +2251,7 @@ static bool32 ShouldUseItem(u32 battler) s32 i; u8 validMons = 0; bool32 shouldUse = FALSE; + u32 healAmount = 0; if (IsAiVsAiBattle()) return FALSE; @@ -2291,10 +2293,12 @@ static bool32 ShouldUseItem(u32 battler) switch (ItemId_GetBattleUsage(item)) { case EFFECT_ITEM_HEAL_AND_CURE_STATUS: - shouldUse = AI_ShouldHeal(battler, 0); + healAmount = GetHPHealAmount(itemEffects[GetItemEffectParamOffset(battler, item, 4, ITEM4_HEAL_HP)], &gEnemyParty[gBattlerPartyIndexes[battler]]); + shouldUse = AI_ShouldHeal(battler, healAmount); break; case EFFECT_ITEM_RESTORE_HP: - shouldUse = AI_ShouldHeal(battler, itemEffects[GetItemEffectParamOffset(battler, item, 4, ITEM4_HEAL_HP)]); + healAmount = GetHPHealAmount(itemEffects[GetItemEffectParamOffset(battler, item, 4, ITEM4_HEAL_HP)], &gEnemyParty[gBattlerPartyIndexes[battler]]); + shouldUse = AI_ShouldHeal(battler, healAmount); break; case EFFECT_ITEM_CURE_STATUS: if (itemEffects[3] & ITEM3_SLEEP && gBattleMons[battler].status1 & STATUS1_SLEEP) @@ -2360,6 +2364,9 @@ static bool32 ShouldUseItem(u32 battler) static bool32 AI_ShouldHeal(u32 battler, u32 healAmount) { bool32 shouldHeal = FALSE; + u8 opponent; + u32 maxDamage = 0; + u32 dmg = 0; if (gBattleMons[battler].hp < gBattleMons[battler].maxHP / 4 || gBattleMons[battler].hp == 0 @@ -2369,6 +2376,30 @@ static bool32 AI_ShouldHeal(u32 battler, u32 healAmount) shouldHeal = !AI_OpponentCanFaintAiWithMod(battler, healAmount); // if target can kill us even after we heal, why bother } + //calculate max expected damage from the opponent + for (opponent = 0; opponent < gBattlersCount; opponent++) + { + if (GetBattlerSide(opponent) == B_SIDE_PLAYER) + { + dmg = GetBestDmgFromBattler(opponent, battler, AI_DEFENDING); + + if (dmg > maxDamage) + maxDamage = dmg; + } + } + + // also heal if a 2HKO is outhealed + if (AI_OpponentCanFaintAiWithMod(battler, 0) + && !AI_OpponentCanFaintAiWithMod(battler, healAmount) + && healAmount > 2*maxDamage) + return TRUE; + + // also heal, if the expected damage is outhealed and it's the last remaining mon + if (AI_OpponentCanFaintAiWithMod(battler, 0) + && !AI_OpponentCanFaintAiWithMod(battler, healAmount) + && CountUsablePartyMons(battler) == 0) + return TRUE; + return shouldHeal; } @@ -2386,3 +2417,28 @@ static bool32 AI_OpponentCanFaintAiWithMod(u32 battler, u32 healAmount) } return FALSE; } + +static u32 GetHPHealAmount(u8 itemEffectParam, struct Pokemon *mon) +{ + switch (itemEffectParam) + { + case ITEM6_HEAL_HP_FULL: + itemEffectParam = GetMonData(mon, MON_DATA_MAX_HP, NULL) - GetMonData(mon, MON_DATA_HP, NULL); + break; + case ITEM6_HEAL_HP_HALF: + itemEffectParam = GetMonData(mon, MON_DATA_MAX_HP, NULL) / 2; + if (itemEffectParam == 0) + itemEffectParam = 1; + break; + case ITEM6_HEAL_HP_LVL_UP: + itemEffectParam = gBattleScripting.levelUpHP; + break; + case ITEM6_HEAL_HP_QUARTER: + itemEffectParam = GetMonData(mon, MON_DATA_MAX_HP, NULL) / 4; + if (itemEffectParam == 0) + itemEffectParam = 1; + break; + } + + return itemEffectParam; +} diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index c9fe300652..93e572a28a 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1350,7 +1350,7 @@ bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dm if (IsMoveUnusable(moveIndex, moves[moveIndex], moveLimitations)) continue; - dmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, AI_DEFENDING, aiData); + dmg = AI_GetDamage(battlerDef, battlerAtk, moveIndex, AI_DEFENDING, aiData); if (dmgMod) dmg *= dmgMod; From 17d851e1f989df33b53f31b53d3e94799e8b9418 Mon Sep 17 00:00:00 2001 From: psf <77138753+pkmnsnfrn@users.noreply.github.com> Date: Thu, 10 Apr 2025 05:59:58 -0700 Subject: [PATCH 07/19] Add B_RUN_TRAINER_BATTLE - players can run from Trainer Battles (#6456) Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> Co-authored-by: Bassoonian --- data/battle_scripts_1.s | 12 +++++++ include/battle_main.h | 2 ++ include/battle_scripts.h | 2 ++ include/config/battle.h | 1 + include/constants/battle_string_ids.h | 4 ++- include/strings.h | 2 ++ src/battle_main.c | 48 +++++++++++++++++++++++++-- src/battle_message.c | 2 ++ src/battle_setup.c | 8 +++-- src/battle_util.c | 4 +++ src/field_screen_effect.c | 19 ++++++++++- src/strings.c | 2 ++ 12 files changed, 100 insertions(+), 6 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 994ba7e6ee..d4ab0e8e61 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -10120,3 +10120,15 @@ BattleScript_SleepClausePreventsEnd:: printstring STRINGID_BLOCKEDBYSLEEPCLAUSE waitmessage B_WAIT_TIME_LONG end2 + +BattleScript_QuestionForfeitBattle:: + printselectionstring STRINGID_QUESTIONFORFEITBATTLE + forfeityesnobox BS_ATTACKER + endselectionscript + +BattleScript_ForfeitBattleGaveMoney:: + getmoneyreward + printstring STRINGID_FORFEITBATTLEGAVEMONEY + waitmessage B_WAIT_TIME_LONG + end2 + diff --git a/include/battle_main.h b/include/battle_main.h index 18f2210588..2d2483d84b 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -87,6 +87,8 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer void ModifyPersonalityForNature(u32 *personality, u32 newNature); u32 GeneratePersonalityForGender(u32 gender, u32 species); void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMon *partyEntry); +bool32 CanPlayerForfeitNormalTrainerBattle(void); +bool32 DidPlayerForfeitNormalTrainerBattle(void); extern struct MultiPartnerMenuPokemon gMultiPartnerParty[MULTI_PARTY_SIZE]; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index e02a562be5..027b69ef1f 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -856,5 +856,7 @@ extern const u8 BattleScript_EffectSpicyExtract[]; extern const u8 BattleScript_DamageToQuarterTargetHP[]; extern const u8 BattleScript_EffectFickleBeam[]; extern const u8 BattleScript_FickleBeamDoubled[]; +extern const u8 BattleScript_QuestionForfeitBattle[]; +extern const u8 BattleScript_ForfeitBattleGaveMoney[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/config/battle.h b/include/config/battle.h index 0aa37db354..33dbade379 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -256,6 +256,7 @@ #define B_HIDE_HEALTHBOX_IN_ANIMS TRUE // If set to TRUE, hides healthboxes during move animations. #define B_WAIT_TIME_MULTIPLIER 16 // This determines how long text pauses in battle last. Vanilla is 16. Lower values result in faster battles. #define B_QUICK_MOVE_CURSOR_TO_RUN FALSE // If set to TRUE, pushing B in the battle options against a wild encounter will move the cursor to the run option +#define B_RUN_TRAINER_BATTLE TRUE // If set to TRUE, players can run from Trainer battles. This is treated as a whiteout. #define B_MOVE_DESCRIPTION_BUTTON L_BUTTON // If set to a button other than B_LAST_USED_BALL_BUTTON, pressing this button will open the move description menu #define B_SHOW_USELESS_Z_MOVE_INFO FALSE // If set to TRUE, Z-moves without additional effects like newer gen status moves will say "no additional effect" #define B_ANIMATE_MON_AFTER_KO TRUE // If set to TRUE, if a Pokémon on the opposite site faints, the non-fainted Pokemon will display a victory animation. diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index db5ee7b16e..9eb09a2fb4 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -732,8 +732,10 @@ #define STRINGID_PKMNGIGANTAMAXED 730 #define STRINGID_TIMETODYNAMAX 731 #define STRINGID_TIMETOGIGANTAMAX 732 +#define STRINGID_QUESTIONFORFEITBATTLE 733 +#define STRINGID_FORFEITBATTLEGAVEMONEY 734 -#define BATTLESTRINGS_COUNT 733 +#define BATTLESTRINGS_COUNT 735 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, diff --git a/include/strings.h b/include/strings.h index 588d513d4b..2bc6b23563 100644 --- a/include/strings.h +++ b/include/strings.h @@ -2414,6 +2414,8 @@ extern const u8 gText_PM[]; // FRLG whiteout extern const u8 gText_PlayerScurriedToCenter[]; extern const u8 gText_PlayerScurriedBackHome[]; +extern const u8 gText_PlayerRegroupCenter[]; +extern const u8 gText_PlayerRegroupHome[]; extern const u8 gText_Relearn[]; // move relearner from summary screen extern const u8 gText_Rename[]; // change nickname from summary screen diff --git a/src/battle_main.c b/src/battle_main.c index d9e811014b..104b49b434 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4230,6 +4230,15 @@ static void HandleTurnActionSelectionState(void) gChosenActionByBattler[battler] = B_ACTION_NOTHING_FAINTED; // Not fainted, but it cannot move, because of the throwing ball. gBattleCommunication[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; } + else if (B_RUN_TRAINER_BATTLE + && gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && position == B_POSITION_PLAYER_RIGHT + && gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] == B_ACTION_RUN + && gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] != B_ACTION_NOTHING_FAINTED) + { + gChosenActionByBattler[battler] = B_ACTION_USE_MOVE; + gBattleCommunication[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; + } else { gBattleStruct->itemPartyIndex[battler] = PARTY_SIZE; @@ -4413,9 +4422,17 @@ static void HandleTurnActionSelectionState(void) gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } + else if (CanPlayerForfeitNormalTrainerBattle() && gBattleResources->bufferB[battler][1] == B_ACTION_RUN) + { + gSelectionBattleScripts[battler] = BattleScript_QuestionForfeitBattle; + gBattleCommunication[battler] = STATE_SELECTION_SCRIPT_MAY_RUN; + gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; + return; + } else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER - && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)) - && gBattleResources->bufferB[battler][1] == B_ACTION_RUN) + && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)) + && gBattleResources->bufferB[battler][1] == B_ACTION_RUN) { BattleScriptExecute(BattleScript_PrintCantRunFromTrainer); gBattleCommunication[battler] = STATE_BEFORE_ACTION_CHOSEN; @@ -5492,6 +5509,11 @@ static void HandleEndTurn_RanFromBattle(void) gBattlescriptCurrInstr = BattleScript_PrintPlayerForfeited; gBattleOutcome = B_OUTCOME_FORFEITED; } + else if (CanPlayerForfeitNormalTrainerBattle()) + { + gBattlescriptCurrInstr = BattleScript_ForfeitBattleGaveMoney; + gBattleOutcome = B_OUTCOME_FORFEITED; + } else { switch (gProtectStructs[gBattlerAttacker].fleeType) @@ -6114,3 +6136,25 @@ static s32 Factorial(s32 n) f *= i; return f; } + +bool32 CanPlayerForfeitNormalTrainerBattle(void) +{ + if (!B_RUN_TRAINER_BATTLE) + return FALSE; + + if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + return FALSE; + + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_INVALID) + return FALSE; + + return (gBattleTypeFlags & BATTLE_TYPE_TRAINER); +} + +bool32 DidPlayerForfeitNormalTrainerBattle(void) +{ + if (!CanPlayerForfeitNormalTrainerBattle()) + return FALSE; + + return (gBattleOutcome == B_OUTCOME_FORFEITED); +} diff --git a/src/battle_message.c b/src/battle_message.c index ccc6ff8963..cf25e7c221 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -896,6 +896,8 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_PKMNGIGANTAMAXED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} grew huge\ninto its Gigantamax form!"), [STRINGID_TIMETODYNAMAX] = COMPOUND_STRING("Time to Dynamax!"), [STRINGID_TIMETOGIGANTAMAX] = COMPOUND_STRING("Time to Gigantamax!"), + [STRINGID_QUESTIONFORFEITBATTLE] = COMPOUND_STRING("Would you like to give up on this battle and quit now? Quitting the battle is the same as losing the battle."), + [STRINGID_FORFEITBATTLEGAVEMONEY] = COMPOUND_STRING("You gave ¥{B_BUFF1} to the winner…{PAUSE_UNTIL_PRESS}"), }; const u16 gTrainerUsedItemStringIds[] = diff --git a/src/battle_setup.c b/src/battle_setup.c index 96d23dc42a..5a96c0b9c3 100644 --- a/src/battle_setup.c +++ b/src/battle_setup.c @@ -1084,9 +1084,9 @@ void ConfigureTwoTrainersBattle(u8 trainerObjEventId, const u8 *trainerScript) gSelectedObjectEvent = trainerObjEventId; gSpecialVar_LastTalked = gObjectEvents[trainerObjEventId].localId; - if (gApproachingTrainerId == 0) + if (gApproachingTrainerId == 0) TrainerBattleLoadArgs(trainerScript + 1); - else + else TrainerBattleLoadArgsSecondTrainer(trainerScript + 1); BattleSetup_ConfigureTrainerBattle(trainerScript + 1); @@ -1264,6 +1264,10 @@ static void CB2_EndTrainerBattle(void) else SetMainCallback2(CB2_WhiteOut); } + else if (DidPlayerForfeitNormalTrainerBattle()) + { + SetMainCallback2(CB2_WhiteOut); + } else { SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic); diff --git a/src/battle_util.c b/src/battle_util.c index c308417191..91e7a7c2d0 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -562,6 +562,10 @@ bool32 TryRunFromBattle(u32 battler) { effect++; } + else if (CanPlayerForfeitNormalTrainerBattle()) + { + effect++; + } else { u8 runningFromBattler = BATTLE_OPPOSITE(battler); diff --git a/src/field_screen_effect.c b/src/field_screen_effect.c index e07d067afc..4d272b9700 100644 --- a/src/field_screen_effect.c +++ b/src/field_screen_effect.c @@ -39,6 +39,7 @@ #include "constants/rgb.h" #include "trainer_hill.h" #include "fldeff.h" +#include "battle.h" static void Task_ExitNonAnimDoor(u8); static void Task_ExitNonDoor(u8); @@ -1342,6 +1343,21 @@ enum { FRLG_WHITEOUT_HEAL_SCRIPT, }; +static const u8 *GenerateRecoveryMessage(u8 taskId) +{ + bool32 forfeitTrainer = DidPlayerForfeitNormalTrainerBattle(); + bool32 destinationIsPlayersHouse = (gTasks[taskId].tIsPlayerHouse == TRUE); + + if (forfeitTrainer && destinationIsPlayersHouse) + return gText_PlayerRegroupHome; + else if (forfeitTrainer && !destinationIsPlayersHouse) + return gText_PlayerRegroupCenter; + else if (!forfeitTrainer && destinationIsPlayersHouse) + return gText_PlayerScurriedBackHome; + else + return gText_PlayerScurriedToCenter; +} + static void Task_RushInjuredPokemonToCenter(u8 taskId) { u32 windowId; @@ -1361,7 +1377,8 @@ static void Task_RushInjuredPokemonToCenter(u8 taskId) break; case FRLG_WHITEOUT_PRINT_MSG: { - const u8 *recoveryMessage = gTasks[taskId].tIsPlayerHouse == TRUE ? gText_PlayerScurriedBackHome : gText_PlayerScurriedToCenter; + const u8 *recoveryMessage = GenerateRecoveryMessage(taskId); + if (PrintWhiteOutRecoveryMessage(taskId, recoveryMessage, 2, 8)) { ObjectEventTurn(&gObjectEvents[gPlayerAvatar.objectEventId], DIR_NORTH); diff --git a/src/strings.c b/src/strings.c index c112db4616..fee143ea68 100644 --- a/src/strings.c +++ b/src/strings.c @@ -806,6 +806,8 @@ const u8 gText_ThankYou[] = _("THANK YOU"); const u8 gText_ByeBye[] = _("BYE-BYE!"); const u8 gText_PlayerScurriedToCenter[] = _("{PLAYER} scurried to a POKéMON CENTER,\nprotecting the exhausted and fainted\nPOKéMON from further harm…\p"); const u8 gText_PlayerScurriedBackHome[] = _("{PLAYER} scurried back home, protecting\nthe exhausted and fainted POKéMON from\nfurther harm…\p"); +const u8 gText_PlayerRegroupCenter[] = _("{PLAYER} went running back to a POKéMON CENTER\nto regroup and reconsider their battle\lstrategy…\p"); +const u8 gText_PlayerRegroupHome[] = _("{PLAYER} went running back home to regroup\nand reconsider their battle strategy…\p"); const u8 gText_HatchedFromEgg[] = _("{STR_VAR_1} hatched from the EGG!"); const u8 gText_NicknameHatchPrompt[] = _("Would you like to nickname the newly\nhatched {STR_VAR_1}?"); ALIGNED(4) const u8 gText_ReadyPickBerry[] = _("Are you ready to BERRY-CRUSH?\nPlease pick a BERRY for use.\p"); From 4aca2fdcd30be40ad68fdaf001ea6f8501bdba35 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Thu, 10 Apr 2025 15:01:02 +0200 Subject: [PATCH 08/19] Refactor fixed damage moves (#6449) Co-authored-by: Bassoonian --- asm/macros/battle_script.inc | 10 ++--- data/battle_scripts_1.s | 43 ---------------------- include/battle_scripts.h | 4 -- include/constants/battle_script_commands.h | 1 - src/battle_ai_util.c | 13 +------ src/battle_script_commands.c | 41 +++++---------------- src/battle_util.c | 39 ++++++++++++++++++++ src/data/battle_move_effects.h | 8 ++-- test/battle/move_effect/level_damage.c | 23 ++++++++++++ 9 files changed, 79 insertions(+), 103 deletions(-) create mode 100644 test/battle/move_effect/level_damage.c diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 5f92d592d2..d30d084a66 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -829,7 +829,7 @@ .4byte \failInstr .endm - .macro damagetohalftargethp + .macro unused_0x94 .byte 0x94 .endm @@ -877,11 +877,11 @@ .byte 0x9e .endm - .macro dmgtolevel + .macro unused_0x9f .byte 0x9f .endm - .macro psywavedamageeffect + .macro unused_0xA0 .byte 0xa0 .endm @@ -2030,10 +2030,6 @@ .4byte \jumpInstr .endm - .macro setargtobattledamage - various BS_ATTACKER, VARIOUS_SET_ARG_TO_BATTLE_DAMAGE - .endm - .macro tryautotomize battler:req, failInstr:req various \battler, VARIOUS_TRY_AUTOTOMIZE .4byte \failInstr diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index d4ab0e8e61..f5f1d948a2 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -3418,16 +3418,6 @@ BattleScript_KOFail:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectSuperFang:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - typecalc - clearmoveresultflags MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE - damagetohalftargethp - goto BattleScript_HitFromAtkAnimation - BattleScript_RecoilIfMiss:: printstring STRINGID_PKMNCRASHED waitmessage B_WAIT_TIME_LONG @@ -3873,28 +3863,6 @@ BattleScript_EffectDisable:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectLevelDamage:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - typecalc - clearmoveresultflags MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE - dmgtolevel - adjustdamage - goto BattleScript_HitFromAtkAnimation - -BattleScript_EffectPsywave:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - typecalc - clearmoveresultflags MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE - psywavedamageeffect - adjustdamage - goto BattleScript_HitFromAtkAnimation - BattleScript_EffectCounter:: attackcanceler counterdamagecalculator BattleScript_FailedFromAtkString @@ -4380,17 +4348,6 @@ BattleScript_EffectBatonPass:: switchineffects BS_ATTACKER goto BattleScript_MoveEnd -BattleScript_EffectFixedDamageArg:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - typecalc - clearmoveresultflags MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE - setargtobattledamage - adjustdamage - goto BattleScript_HitFromAtkAnimation - BattleScript_EffectMorningSun:: BattleScript_EffectSynthesis:: BattleScript_EffectMoonlight:: diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 027b69ef1f..d67fa47be4 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -592,8 +592,6 @@ extern const u8 BattleScript_EffectToxic[]; extern const u8 BattleScript_EffectLightScreen[]; extern const u8 BattleScript_EffectRest[]; extern const u8 BattleScript_EffectOHKO[]; -extern const u8 BattleScript_EffectSuperFang[]; -extern const u8 BattleScript_EffectFixedDamageArg[]; extern const u8 BattleScript_EffectHealBlock[]; extern const u8 BattleScript_RecoilIfMiss[]; extern const u8 BattleScript_EffectMist[]; @@ -628,8 +626,6 @@ extern const u8 BattleScript_EffectHoldHands[]; extern const u8 BattleScript_EffectCelebrate[]; extern const u8 BattleScript_EffectHappyHour[]; extern const u8 BattleScript_EffectDisable[]; -extern const u8 BattleScript_EffectLevelDamage[]; -extern const u8 BattleScript_EffectPsywave[]; extern const u8 BattleScript_EffectCounter[]; extern const u8 BattleScript_EffectEncore[]; extern const u8 BattleScript_EffectPainSplit[]; diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index b0cccc2626..c59b0ee170 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -134,7 +134,6 @@ enum CmdVarious VARIOUS_TRY_ELECTRIFY, VARIOUS_TRY_SOAK, VARIOUS_TRY_LAST_RESORT, - VARIOUS_SET_ARG_TO_BATTLE_DAMAGE, VARIOUS_TRY_AUTOTOMIZE, VARIOUS_ABILITY_POPUP, VARIOUS_JUMP_IF_TARGET_ALLY, diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 93e572a28a..d9a1713e32 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -174,6 +174,7 @@ void RecordKnownMove(u32 battlerId, u32 move) s32 i; for (i = 0; i < MAX_MON_MOVES; i++) { + if (BATTLE_HISTORY->usedMoves[battlerId][i] == move) break; if (BATTLE_HISTORY->usedMoves[battlerId][i] == MOVE_NONE) @@ -577,15 +578,6 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal switch (effect) { - case EFFECT_LEVEL_DAMAGE: - median = maximum = minimum = gBattleMons[damageCalcData->battlerAtk].level; - break; - case EFFECT_PSYWAVE: - median = maximum = minimum = gBattleMons[damageCalcData->battlerAtk].level; - break; - case EFFECT_FIXED_DAMAGE_ARG: - median = maximum = minimum = GetMoveFixedDamage(move); - break; case EFFECT_MULTI_HIT: if (move == MOVE_WATER_SHURIKEN && gBattleMons[damageCalcData->battlerAtk].species == SPECIES_GRENINJA_ASH) { @@ -617,9 +609,6 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal // If target has less HP than user, Endeavor does no damage median = maximum = minimum = max(0, gBattleMons[damageCalcData->battlerDef].hp - gBattleMons[damageCalcData->battlerAtk].hp); break; - case EFFECT_SUPER_FANG: - median = maximum = minimum = max(1, gBattleMons[damageCalcData->battlerDef].hp / 2); - break; case EFFECT_FINAL_GAMBIT: median = maximum = minimum = gBattleMons[damageCalcData->battlerAtk].hp; break; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index d5c64a57ed..dca87252e0 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -494,7 +494,7 @@ static void Cmd_tryconversiontypechange(void); static void Cmd_givepaydaymoney(void); static void Cmd_setlightscreen(void); static void Cmd_tryKO(void); -static void Cmd_damagetohalftargethp(void); +static void Cmd_unused_0x94(void); static void Cmd_copybidedmg(void); static void Cmd_unused_96(void); static void Cmd_tryinfatuating(void); @@ -505,8 +505,8 @@ static void Cmd_transformdataexecution(void); static void Cmd_setsubstitute(void); static void Cmd_mimicattackcopy(void); static void Cmd_metronome(void); -static void Cmd_dmgtolevel(void); -static void Cmd_psywavedamageeffect(void); +static void Cmd_unused_0x9f(void); +static void Cmd_unused_0xA0(void); static void Cmd_counterdamagecalculator(void); static void Cmd_mirrorcoatdamagecalculator(void); static void Cmd_disablelastusedattack(void); @@ -753,7 +753,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_givepaydaymoney, //0x91 Cmd_setlightscreen, //0x92 Cmd_tryKO, //0x93 - Cmd_damagetohalftargethp, //0x94 + Cmd_unused_0x94, //0x94 Cmd_copybidedmg, //0x95 Cmd_unused_96, //0x96 Cmd_tryinfatuating, //0x97 @@ -764,8 +764,8 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_setsubstitute, //0x9C Cmd_mimicattackcopy, //0x9D Cmd_metronome, //0x9E - Cmd_dmgtolevel, //0x9F - Cmd_psywavedamageeffect, //0xA0 + Cmd_unused_0x9f, //0x9F + Cmd_unused_0xA0, //0xA0 Cmd_counterdamagecalculator, //0xA1 Cmd_mirrorcoatdamagecalculator, //0xA2 Cmd_disablelastusedattack, //0xA3 @@ -11021,12 +11021,6 @@ static void Cmd_various(void) gBattlescriptCurrInstr = cmd->failInstr; return; } - case VARIOUS_SET_ARG_TO_BATTLE_DAMAGE: - { - VARIOUS_ARGS(); - gBattleStruct->moveDamage[gBattlerTarget] = GetMoveFixedDamage(gCurrentMove); - break; - } case VARIOUS_TRY_AUTOTOMIZE: { VARIOUS_ARGS(const u8 *failInstr); @@ -13195,16 +13189,8 @@ static void Cmd_tryKO(void) #undef FOCUS_BANDED #undef AFFECTION_ENDURED -// Super Fang -static void Cmd_damagetohalftargethp(void) +static void Cmd_unused_0x94(void) { - CMD_ARGS(); - - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxHP(gBattlerTarget) / 2; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; - - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_copybidedmg(void) @@ -13515,21 +13501,12 @@ static void Cmd_metronome(void) ResetValuesForCalledMove(); } -static void Cmd_dmgtolevel(void) +static void Cmd_unused_0x9f(void) { - CMD_ARGS(); - - gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerAttacker].level; - gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_psywavedamageeffect(void) +static void Cmd_unused_0xA0(void) { - CMD_ARGS(); - - s32 randDamage = B_PSYWAVE_DMG >= GEN_6 ? (Random() % 101) : ((Random() % 11) * 10); - gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerAttacker].level * (randDamage + 50) / 100; - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_counterdamagecalculator(void) diff --git a/src/battle_util.c b/src/battle_util.c index 91e7a7c2d0..8c60271c43 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -10499,6 +10499,37 @@ s32 ApplyModifiersAfterDmgRoll(s32 dmg, struct DamageCalculationData *damageCalc return dmg; } +static inline s32 DoFixedDamageMoveCalc(struct DamageCalculationData *damageCalcData) +{ + s32 dmg = 0; + + switch (GetMoveEffect(damageCalcData->move)) + { + case EFFECT_LEVEL_DAMAGE: + dmg = gBattleMons[damageCalcData->battlerAtk].level; + break; + case EFFECT_PSYWAVE: + s32 randDamage = B_PSYWAVE_DMG >= GEN_6 ? (Random() % 101) : ((Random() % 11) * 10); + dmg = gBattleMons[damageCalcData->battlerAtk].level * (randDamage + 50) / 100; + break; + case EFFECT_FIXED_DAMAGE_ARG: + dmg = GetMoveFixedDamage(damageCalcData->move); + break; + case EFFECT_SUPER_FANG: + dmg = GetNonDynamaxHP(gBattlerTarget) / 2; + break; + default: + return INT32_MAX; + } + + gBattleStruct->moveResultFlags[damageCalcData->battlerDef] &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE); + + if (dmg == 0) + dmg = 1; + + return dmg; +} + static inline s32 DoMoveDamageCalc(struct DamageCalculationData *damageCalcData, u32 fixedBasePower, uq4_12_t typeEffectivenessModifier, u32 weather) { u32 holdEffectAtk, holdEffectDef, abilityAtk, abilityDef; @@ -10506,6 +10537,10 @@ static inline s32 DoMoveDamageCalc(struct DamageCalculationData *damageCalcData, if (typeEffectivenessModifier == UQ_4_12(0.0)) return 0; + s32 dmg = DoFixedDamageMoveCalc(damageCalcData); + if (dmg != INT32_MAX) + return dmg; + holdEffectAtk = GetBattlerHoldEffect(damageCalcData->battlerAtk, TRUE); holdEffectDef = GetBattlerHoldEffect(damageCalcData->battlerDef, TRUE); abilityAtk = GetBattlerAbility(damageCalcData->battlerAtk); @@ -10614,6 +10649,10 @@ s32 CalculateMoveDamage(struct DamageCalculationData *damageCalcData, u32 fixedB s32 CalculateMoveDamageVars(struct DamageCalculationData *damageCalcData, u32 fixedBasePower, uq4_12_t typeEffectivenessModifier, u32 weather, u32 holdEffectAtk, u32 holdEffectDef, u32 abilityAtk, u32 abilityDef) { + s32 dmg = DoFixedDamageMoveCalc(damageCalcData); + if (dmg != INT32_MAX) + return dmg; + return DoMoveDamageCalcVars(damageCalcData, fixedBasePower, typeEffectivenessModifier, weather, holdEffectAtk, holdEffectDef, abilityAtk, abilityDef); } diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index dc0413af2d..38928c4f4c 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -218,14 +218,14 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_SUPER_FANG] = { - .battleScript = BattleScript_EffectSuperFang, + .battleScript = BattleScript_EffectHit, .battleTvScore = 5, .encourageEncore = TRUE, }, [EFFECT_FIXED_DAMAGE_ARG] = { - .battleScript = BattleScript_EffectFixedDamageArg, + .battleScript = BattleScript_EffectHit, .battleTvScore = 1, }, @@ -454,13 +454,13 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_LEVEL_DAMAGE] = { - .battleScript = BattleScript_EffectLevelDamage, + .battleScript = BattleScript_EffectHit, .battleTvScore = 2, }, [EFFECT_PSYWAVE] = { - .battleScript = BattleScript_EffectPsywave, + .battleScript = BattleScript_EffectHit, .battleTvScore = 1, }, diff --git a/test/battle/move_effect/level_damage.c b/test/battle/move_effect/level_damage.c new file mode 100644 index 0000000000..2ccf1ae964 --- /dev/null +++ b/test/battle/move_effect/level_damage.c @@ -0,0 +1,23 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_SEISMIC_TOSS) == EFFECT_LEVEL_DAMAGE); +} + +SINGLE_BATTLE_TEST("Level Damage: Seismic Toss deals damage based on user's level") +{ + s16 dmg; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Level(50); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SEISMIC_TOSS); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SEISMIC_TOSS, player); + HP_BAR(opponent, captureDamage: &dmg); + } THEN { + EXPECT(dmg == 50); + } +} From 7ff50e358616be135ab5337a8fa33bea24ea941e Mon Sep 17 00:00:00 2001 From: psf <77138753+pkmnsnfrn@users.noreply.github.com> Date: Thu, 10 Apr 2025 06:38:51 -0700 Subject: [PATCH 09/19] Fix broken links in merge_checklist.md (#6570) --- docs/team_procedures/merge_checklist.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/team_procedures/merge_checklist.md b/docs/team_procedures/merge_checklist.md index 8af4247411..107f5a0f9f 100644 --- a/docs/team_procedures/merge_checklist.md +++ b/docs/team_procedures/merge_checklist.md @@ -37,18 +37,18 @@ If you're not sure if something CAN be tested, start a discussion. Some contribu If any new tests are `KNOWN_FAILING`, issues should be opened describing each of the `KNOWN_FAILING` tests and our understanding of why they fail. -## Does the branch meet our [config philosophy](docs/styleguide#config-philosophy)? +## Does the branch meet our [config philosophy](/docs/STYLEGUIDE.md#config-philosophy)? -## Does the branch meet our [saves philosophy](docs/styleguide#saves-philosophy)? +## Does the branch meet our [saves philosophy](/docs/STYLEGUIDE.md#saves-philosophy)? -## Does the submitted code follow the [styleguide](docs/styleguide)? +## Does the submitted code follow the [styleguide](/docs/STYLEGUIDE.md)? This applies to code that comes from other branches or games. ## Is the pull request appropriately labeled? Without labels, the CHANGELOG will not be properly formatted. For specifically the `bugfix` label, an additional label, detailing what area the bug exists in is required. ## Is `pokeemerald-expansion` free from a merge freeze? -Our [release schedule](docs/team_procedures/schedule.md) prevents us from merging Big Features and non-bugfixes within certain dates close to a release. Please use `/release` in the RHH Discord to clarify when these are occuring. +Our [release schedule](/docs/team_procedures/schedule.md) prevents us from merging Big Features and non-bugfixes within certain dates close to a release. Please use `/release` in the RHH Discord to clarify when these are occuring. # Merging From 8bdad342117ff7d29d2aa1dd96dd07935b17ba43 Mon Sep 17 00:00:00 2001 From: khbsd Date: Thu, 10 Apr 2025 12:27:44 -0500 Subject: [PATCH 10/19] fix: missing break statement (#6572) --- src/wild_encounter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 3a3a7d8dc7..3db2402d2f 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -1182,6 +1182,7 @@ static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, u16 default: case WILD_AREA_FISHING: case WILD_AREA_HIDDEN: + break; } for (i = 0; i < numMon; i++) From c1ad43b1cce3e0795992e5cc7e3182f224c13afb Mon Sep 17 00:00:00 2001 From: khbsd Date: Thu, 10 Apr 2025 14:43:21 -0500 Subject: [PATCH 11/19] Adds SHOW_TYPES_SEEN to the B_SHOW_TYPES option (#6561) --- include/config/battle.h | 9 +++++---- include/type_icons.h | 2 +- src/battle_main.c | 17 ++++------------- src/type_icons.c | 24 ++++++++++++++++++++---- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/include/config/battle.h b/include/config/battle.h index 33dbade379..b61494ee44 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -317,10 +317,11 @@ #define B_ENEMY_THROW_BALLS_SOUND GEN_LATEST // In GEN_5+, enemy Trainer's Poké Balls make a sound when thrown to send out a Pokémon. This can only be used when B_ENEMY_THROW_BALLS is set to GEN_6 or later. #define B_PLAYER_THROW_BALLS_SOUND GEN_LATEST // In GEN_5+, the player's Poké Balls make a sound when thrown to send out a Pokémon. -#define SHOW_TYPES_NEVER 0 -#define SHOW_TYPES_ALWAYS 1 -#define SHOW_TYPES_CAUGHT 2 -#define B_SHOW_TYPES SHOW_TYPES_NEVER // When defined as SHOW_TYPES_ALWAYS, after selecting "Fight" in battle, the types of all Pokemon are revealed. Whe defined as SHOW_TYPES_OWN, types are only revealed if the player owns the mon in question. +#define SHOW_TYPES_NEVER 0 // Never shows types in battle +#define SHOW_TYPES_ALWAYS 1 // Always show types in battle +#define SHOW_TYPES_CAUGHT 2 // Only show types if you've caught a species of the mon. +#define SHOW_TYPES_SEEN 3 // Only show types if you've seen a species of the mon. +#define B_SHOW_TYPES SHOW_TYPES_NEVER // When to show type indicators next to Pokémon health bars in battle, while choosing a move after selecting a target Pokémon. // Pokémon battle sprite settings #define B_ENEMY_MON_SHADOW_STYLE GEN_LATEST // In Gen4+, all enemy Pokemon will have a shadow drawn beneath them. diff --git a/include/type_icons.h b/include/type_icons.h index 1d6a312f07..c84e44f53d 100644 --- a/include/type_icons.h +++ b/include/type_icons.h @@ -1,7 +1,7 @@ #ifndef GUARD_TYPE_ICONS_H #define GUARD_TYPE_ICONS_H -void LoadTypeIcons(u32); +void LoadTypeIcons(u32 battler); #define TYPE_ICON_TAG 0x2720 #define TYPE_ICON_TAG_2 0x2721 diff --git a/src/battle_main.c b/src/battle_main.c index 104b49b434..acc6e6f454 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3696,19 +3696,6 @@ static void DoBattleIntro(void) case BATTLE_INTRO_STATE_SET_DEX_AND_BATTLE_VARS: if (!gBattleControllerExecFlags) { - for (battler = 0; battler < gBattlersCount; battler++) - { - if (GetBattlerSide(battler) == B_SIDE_OPPONENT - && !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_LINK - | BATTLE_TYPE_RECORDED_LINK - | BATTLE_TYPE_TRAINER_HILL))) - { - HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality); - } - } - gBattleStruct->eventsBeforeFirstTurnState = 0; gBattleStruct->switchInBattlerCounter = 0; gBattleStruct->overworldWeatherDone = FALSE; @@ -5572,6 +5559,10 @@ static void HandleEndTurn_FinishBattle(void) GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_NICKNAME, gBattleResults.playerMon2Name); } } + else if (GetBattlerSide(battler) == B_SIDE_OPPONENT) + { + HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality); + } } TryPutPokemonTodayOnAir(); } diff --git a/src/type_icons.c b/src/type_icons.c index 41fa102bb9..febf2346a4 100644 --- a/src/type_icons.c +++ b/src/type_icons.c @@ -15,7 +15,8 @@ static void LoadTypeIconsPerBattler(u32, u32); static bool32 UseDoubleBattleCoords(u32); static u32 GetMonPublicType(u32, u32); -static bool32 ShouldHideUncaughtType(u32); +static bool32 ShouldHideUncaughtType(u32 species); +static bool32 ShouldHideUnseenType(u32 species); static u32 GetMonDefensiveTeraType(struct Pokemon *, struct Pokemon*, u32, u32, u32, u32); static u32 IsIllusionActiveAndTypeUnchanged(struct Pokemon*, u32, u32); @@ -239,7 +240,11 @@ void LoadTypeIcons(u32 battler) { u32 position; - if (B_SHOW_TYPES == SHOW_TYPES_NEVER) + struct Pokemon* mon = GetPartyBattlerData(battler); + u32 species = GetMonData(mon, MON_DATA_SPECIES, NULL); + + if (B_SHOW_TYPES == SHOW_TYPES_NEVER + || (B_SHOW_TYPES == SHOW_TYPES_SEEN && !GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_SEEN))) return; LoadTypeSpritesAndPalettes(); @@ -296,7 +301,7 @@ static u32 GetMonPublicType(u32 battlerId, u32 typeNum) struct Pokemon* monIllusion; u32 illusionSpecies; - if (ShouldHideUncaughtType(monSpecies)) + if (ShouldHideUncaughtType(monSpecies) || ShouldHideUnseenType(monSpecies)) return TYPE_MYSTERY; monIllusion = GetIllusionMonPtr(battlerId); @@ -316,7 +321,18 @@ static bool32 ShouldHideUncaughtType(u32 species) if (B_SHOW_TYPES != SHOW_TYPES_CAUGHT) return FALSE; - if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species),FLAG_GET_CAUGHT)) + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + return FALSE; + + return TRUE; +} + +static bool32 ShouldHideUnseenType(u32 species) +{ + if (B_SHOW_TYPES != SHOW_TYPES_SEEN) + return FALSE; + + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_SEEN)) return FALSE; return TRUE; From cf98d764ad24ad3559591c3648c1f11d6fd677ab Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Thu, 10 Apr 2025 23:56:26 +0200 Subject: [PATCH 12/19] Gimmick Indicator refactor (#6553) Co-authored-by: Hedara --- include/battle_gimmick.h | 4 +- src/battle_gimmick.c | 53 +++++++++-------- src/battle_interface.c | 2 +- src/data/gimmicks.h | 12 ++-- src/data/graphics/gimmicks.h | 108 +++++++++++++++++++++++------------ 5 files changed, 108 insertions(+), 71 deletions(-) diff --git a/include/battle_gimmick.h b/include/battle_gimmick.h index de1352a611..d0e975462a 100644 --- a/include/battle_gimmick.h +++ b/include/battle_gimmick.h @@ -17,8 +17,8 @@ struct GimmickInfo const struct SpritePalette *triggerPal; // trigger gfx data const struct SpriteSheet *triggerSheet; const struct SpriteTemplate *triggerTemplate; - const struct SpritePalette *indicatorPal; // indicator gfx data - const struct SpriteSheet *indicatorSheet; + const u32 indicatorPalTag; + const u8 *indicatorData; bool32 (*CanActivate)(u32 battler); void (*ActivateGimmick)(u32 battler); }; diff --git a/src/battle_gimmick.c b/src/battle_gimmick.c index 0b725811ee..4cdc754ea4 100644 --- a/src/battle_gimmick.c +++ b/src/battle_gimmick.c @@ -265,20 +265,9 @@ static void SpriteCb_GimmickTrigger(struct Sprite *sprite) void LoadIndicatorSpritesGfx(void) { - u32 gimmick; - for (gimmick = 0; gimmick < GIMMICKS_COUNT; ++gimmick) - { - if (gimmick == GIMMICK_TERA) // special case - LoadSpriteSheets(sTeraIndicatorSpriteSheets); - else if (gGimmicksInfo[gimmick].indicatorSheet != NULL) - LoadSpriteSheet(gGimmicksInfo[gimmick].indicatorSheet); - - if (gGimmicksInfo[gimmick].indicatorPal != NULL) - LoadSpritePalette(gGimmicksInfo[gimmick].indicatorPal); - } - // Primal reversion graphics aren't loaded as part of gimmick data - LoadSpriteSheet(&sSpriteSheet_AlphaIndicator); - LoadSpriteSheet(&sSpriteSheet_OmegaIndicator); + LoadSpritePalette(&sSpritePalette_MiscIndicator); + LoadSpritePalette(&sSpritePalette_MegaIndicator); + LoadSpritePalette(&sSpritePalette_TeraIndicator); } static void SpriteCb_GimmickIndicator(struct Sprite *sprite) @@ -295,28 +284,28 @@ static inline u32 GetIndicatorSpriteId(u32 healthboxId) return gBattleStruct->gimmick.indicatorSpriteId[gSprites[healthboxId].hMain_Battler]; } -u32 GetIndicatorTileTag(u32 battler) +const u32 *GetIndicatorSpriteSrc(u32 battler) { u32 gimmick = GetActiveGimmick(battler); if (IsBattlerPrimalReverted(battler)) { if (gBattleMons[battler].species == SPECIES_GROUDON_PRIMAL) - return TAG_OMEGA_INDICATOR_TILE; + return (u32 *)&sOmegaIndicatorGfx; else - return TAG_ALPHA_INDICATOR_TILE; + return (u32 *)&sAlphaIndicatorGfx; } else if (gimmick == GIMMICK_TERA) // special case { - return sTeraIndicatorSpriteSheets[GetBattlerTeraType(battler)].tag; + return (u32 *)sTeraIndicatorDataPtrs[GetBattlerTeraType(battler)]; } - else if (gGimmicksInfo[gimmick].indicatorSheet != NULL) + else if (gGimmicksInfo[gimmick].indicatorData != NULL) { - return gGimmicksInfo[gimmick].indicatorSheet->tag; + return (u32 *)gGimmicksInfo[gimmick].indicatorData; } else { - return TAG_NONE; + return NULL; } } @@ -325,27 +314,34 @@ u32 GetIndicatorPalTag(u32 battler) u32 gimmick = GetActiveGimmick(battler); if (IsBattlerPrimalReverted(battler)) return TAG_MISC_INDICATOR_PAL; - else if (gGimmicksInfo[gimmick].indicatorPal != NULL) - return gGimmicksInfo[gimmick].indicatorPal->tag; + else if (gGimmicksInfo[gimmick].indicatorPalTag != 0) + return gGimmicksInfo[gimmick].indicatorPalTag; else return TAG_NONE; } +#define INDICATOR_SIZE (8 * 16 / 2) + void UpdateIndicatorVisibilityAndType(u32 healthboxId, bool32 invisible) { u32 battler = gSprites[healthboxId].hMain_Battler; - u32 tileTag = GetIndicatorTileTag(battler); u32 palTag = GetIndicatorPalTag(battler); struct Sprite *sprite = &gSprites[GetIndicatorSpriteId(healthboxId)]; if (GetIndicatorSpriteId(healthboxId) == 0) // safari zone means the player doesn't have an indicator sprite id return; - if (tileTag != TAG_NONE && palTag != TAG_NONE) + if (palTag != TAG_NONE) { - sprite->oam.tileNum = GetSpriteTileStartByTag(tileTag); sprite->oam.paletteNum = IndexOfSpritePaletteTag(palTag); sprite->invisible = invisible; + + u32 *dst = (u32 *)(OBJ_VRAM0 + TILE_SIZE_4BPP * GetSpriteTileStartByTag(BATTLER_INDICATOR_TAG + battler)); + + const u32 *src = GetIndicatorSpriteSrc(battler); + + for (u32 i = 0; i < INDICATOR_SIZE / 4; i++) + dst[i] = src[i]; } else // in case of error { @@ -353,6 +349,8 @@ void UpdateIndicatorVisibilityAndType(u32 healthboxId, bool32 invisible) } } +#undef INDICATOR_SIZE + void UpdateIndicatorOamPriority(u32 healthboxId, u32 oamPriority) { gSprites[GetIndicatorSpriteId(healthboxId)].oam.priority = oamPriority; @@ -389,7 +387,8 @@ void CreateIndicatorSprite(u32 battler) x = sIndicatorPositions[position][0]; y += sIndicatorPositions[position][1]; - spriteId = CreateSpriteAtEnd(&sSpriteTemplate_GimmickIndicator, 0, y, 0); + LoadSpriteSheet(&sBattler_GimmickSpritesheets[battler]); + spriteId = CreateSprite(&(sSpriteTemplate_BattlerIndicators[battler]), 0, y, 0); gBattleStruct->gimmick.indicatorSpriteId[battler] = spriteId; gSprites[spriteId].tBattler = battler; gSprites[spriteId].tPosX = x; diff --git a/src/battle_interface.c b/src/battle_interface.c index d20848f321..1f85e68eea 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -922,7 +922,7 @@ static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl) u8 battler = gSprites[healthboxSpriteId].hMain_Battler; // Don't print Lv char if mon has a gimmick with an indicator active. - if (GetIndicatorTileTag(battler) != TAG_NONE) + if (GetIndicatorPalTag(battler) != TAG_NONE) { objVram = ConvertIntToDecimalStringN(text, lvl, STR_CONV_MODE_LEFT_ALIGN, 3); xPos = 5 * (3 - (objVram - (text + 2))) - 1; diff --git a/src/data/gimmicks.h b/src/data/gimmicks.h index 5b06feddef..0ea19ea1e4 100644 --- a/src/data/gimmicks.h +++ b/src/data/gimmicks.h @@ -10,8 +10,8 @@ const struct GimmickInfo gGimmicksInfo[GIMMICKS_COUNT] = .triggerSheet = &sSpriteSheet_MegaTrigger, .triggerPal = &sSpritePalette_MegaTrigger, .triggerTemplate = &sSpriteTemplate_GimmickTrigger, - .indicatorSheet = &sSpriteSheet_MegaIndicator, - .indicatorPal = &sSpritePalette_MegaIndicator, + .indicatorData = sMegaIndicatorGfx, + .indicatorPalTag = TAG_MEGA_INDICATOR_PAL, .CanActivate = CanMegaEvolve, .ActivateGimmick = ActivateMegaEvolution, }, @@ -36,8 +36,8 @@ const struct GimmickInfo gGimmicksInfo[GIMMICKS_COUNT] = .triggerSheet = &sSpriteSheet_DynamaxTrigger, .triggerPal = &sSpritePalette_DynamaxTrigger, .triggerTemplate = &sSpriteTemplate_GimmickTrigger, - .indicatorSheet = &sSpriteSheet_DynamaxIndicator, - .indicatorPal = &sSpritePalette_MiscIndicator, + .indicatorData = sDynamaxIndicatorGfx, + .indicatorPalTag = TAG_MISC_INDICATOR_PAL, .CanActivate = CanDynamax, .ActivateGimmick = ActivateDynamax, }, @@ -46,8 +46,8 @@ const struct GimmickInfo gGimmicksInfo[GIMMICKS_COUNT] = .triggerSheet = &sSpriteSheet_TeraTrigger, .triggerPal = &sSpritePalette_TeraTrigger, .triggerTemplate = &sSpriteTemplate_GimmickTrigger, - .indicatorSheet = NULL, // handled separately - .indicatorPal = &sSpritePalette_TeraIndicator, + .indicatorData = NULL, // handled separately + .indicatorPalTag = TAG_TERA_INDICATOR_PAL, .CanActivate = CanTerastallize, .ActivateGimmick = ActivateTera, } diff --git a/src/data/graphics/gimmicks.h b/src/data/graphics/gimmicks.h index f16b2f83c0..483cf2218b 100644 --- a/src/data/graphics/gimmicks.h +++ b/src/data/graphics/gimmicks.h @@ -99,34 +99,29 @@ static const u16 sMiscIndicatorPal[] = INCBIN_U16("graphics/battle_interface/mis static const u16 sMegaIndicatorPal[] = INCBIN_U16("graphics/battle_interface/mega_indicator.gbapal"); static const u16 sTeraIndicatorPal[] = INCBIN_U16("graphics/battle_interface/tera_indicator.gbapal"); -static const struct SpriteSheet sSpriteSheet_MegaIndicator = {sMegaIndicatorGfx, sizeof(sMegaIndicatorGfx), TAG_MEGA_INDICATOR_TILE}; -static const struct SpriteSheet sSpriteSheet_AlphaIndicator = {sAlphaIndicatorGfx, sizeof(sAlphaIndicatorGfx), TAG_ALPHA_INDICATOR_TILE}; -static const struct SpriteSheet sSpriteSheet_OmegaIndicator = {sOmegaIndicatorGfx, sizeof(sOmegaIndicatorGfx), TAG_OMEGA_INDICATOR_TILE}; -static const struct SpriteSheet sSpriteSheet_DynamaxIndicator = {sDynamaxIndicatorGfx, sizeof(sDynamaxIndicatorGfx), TAG_DYNAMAX_INDICATOR_TILE}; -static const struct SpriteSheet sTeraIndicatorSpriteSheets[NUMBER_OF_MON_TYPES + 1] = +static const u8 *sTeraIndicatorDataPtrs[] = { - {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), TAG_NORMAL_INDICATOR_TILE}, // TYPE_NONE - {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), TAG_NORMAL_INDICATOR_TILE}, - {sFightingIndicatorGfx, sizeof(sFightingIndicatorGfx), TAG_FIGHTING_INDICATOR_TILE}, - {sFlyingIndicatorGfx, sizeof(sFlyingIndicatorGfx), TAG_FLYING_INDICATOR_TILE}, - {sPoisonIndicatorGfx, sizeof(sPoisonIndicatorGfx), TAG_POISON_INDICATOR_TILE}, - {sGroundIndicatorGfx, sizeof(sGroundIndicatorGfx), TAG_GROUND_INDICATOR_TILE}, - {sRockIndicatorGfx, sizeof(sRockIndicatorGfx), TAG_ROCK_INDICATOR_TILE}, - {sBugIndicatorGfx, sizeof(sBugIndicatorGfx), TAG_BUG_INDICATOR_TILE}, - {sGhostIndicatorGfx, sizeof(sGhostIndicatorGfx), TAG_GHOST_INDICATOR_TILE}, - {sSteelIndicatorGfx, sizeof(sSteelIndicatorGfx), TAG_STEEL_INDICATOR_TILE}, - {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), TAG_NORMAL_INDICATOR_TILE}, // TYPE_MYSTERY - {sFireIndicatorGfx, sizeof(sFireIndicatorGfx), TAG_FIRE_INDICATOR_TILE}, - {sWaterIndicatorGfx, sizeof(sWaterIndicatorGfx), TAG_WATER_INDICATOR_TILE}, - {sGrassIndicatorGfx, sizeof(sGrassIndicatorGfx), TAG_GRASS_INDICATOR_TILE}, - {sElectricIndicatorGfx, sizeof(sElectricIndicatorGfx), TAG_ELECTRIC_INDICATOR_TILE}, - {sPsychicIndicatorGfx, sizeof(sPsychicIndicatorGfx), TAG_PSYCHIC_INDICATOR_TILE}, - {sIceIndicatorGfx, sizeof(sIceIndicatorGfx), TAG_ICE_INDICATOR_TILE}, - {sDragonIndicatorGfx, sizeof(sDragonIndicatorGfx), TAG_DRAGON_INDICATOR_TILE}, - {sDarkIndicatorGfx, sizeof(sDarkIndicatorGfx), TAG_DARK_INDICATOR_TILE}, - {sFairyIndicatorGfx, sizeof(sFairyIndicatorGfx), TAG_FAIRY_INDICATOR_TILE}, - {sStellarIndicatorGfx, sizeof(sStellarIndicatorGfx), TAG_STELLAR_INDICATOR_TILE}, - {0} + sNormalIndicatorGfx, + sNormalIndicatorGfx, + sFightingIndicatorGfx, + sFlyingIndicatorGfx, + sPoisonIndicatorGfx, + sGroundIndicatorGfx, + sRockIndicatorGfx, + sBugIndicatorGfx, + sGhostIndicatorGfx, + sSteelIndicatorGfx, + sNormalIndicatorGfx, + sFireIndicatorGfx, + sWaterIndicatorGfx, + sGrassIndicatorGfx, + sElectricIndicatorGfx, + sPsychicIndicatorGfx, + sIceIndicatorGfx, + sDragonIndicatorGfx, + sDarkIndicatorGfx, + sFairyIndicatorGfx, + sStellarIndicatorGfx, }; static const struct SpritePalette sSpritePalette_MiscIndicator = {sMiscIndicatorPal, TAG_MISC_INDICATOR_PAL}; @@ -141,13 +136,56 @@ static const struct OamData sOamData_GimmickIndicator = }; static void SpriteCb_GimmickIndicator(struct Sprite *sprite); -static const struct SpriteTemplate sSpriteTemplate_GimmickIndicator = + +#define BATTLER_INDICATOR_TAG 0xDEDE +static const struct SpriteSheet sBattler_GimmickSpritesheets[] = { - .tileTag = TAG_NORMAL_INDICATOR_TILE, // updated dynamically - .paletteTag = TAG_TERA_INDICATOR_PAL, // updated dynamically - .oam = &sOamData_GimmickIndicator, - .anims = gDummySpriteAnimTable, - .images = NULL, - .affineAnims = gDummySpriteAffineAnimTable, - .callback = SpriteCb_GimmickIndicator, + {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), BATTLER_INDICATOR_TAG}, + {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), BATTLER_INDICATOR_TAG+1}, + {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), BATTLER_INDICATOR_TAG+2}, + {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), BATTLER_INDICATOR_TAG+3}, +}; + +static const struct SpriteTemplate sSpriteTemplate_BattlerIndicators[] = +{ + [0] = + { + .tileTag = BATTLER_INDICATOR_TAG, // updated dynamically + .paletteTag = TAG_TERA_INDICATOR_PAL, // updated dynamically + .oam = &sOamData_GimmickIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_GimmickIndicator, + }, + [1] = + { + .tileTag = BATTLER_INDICATOR_TAG + 1, // updated dynamically + .paletteTag = TAG_TERA_INDICATOR_PAL, // updated dynamically + .oam = &sOamData_GimmickIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_GimmickIndicator, + }, + [2] = + { + .tileTag = BATTLER_INDICATOR_TAG + 2, // updated dynamically + .paletteTag = TAG_TERA_INDICATOR_PAL, // updated dynamically + .oam = &sOamData_GimmickIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_GimmickIndicator, + }, + [3] = + { + .tileTag = BATTLER_INDICATOR_TAG + 3, // updated dynamically + .paletteTag = TAG_TERA_INDICATOR_PAL, // updated dynamically + .oam = &sOamData_GimmickIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_GimmickIndicator, + }, }; From a243b97907452db252f3725438eff041146d4b02 Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Fri, 11 Apr 2025 12:52:12 +0200 Subject: [PATCH 13/19] Documentation (#6576) Co-authored-by: Hedara --- docs/tutorials/how_to_new_pokemon.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/tutorials/how_to_new_pokemon.md b/docs/tutorials/how_to_new_pokemon.md index b8a99520ec..de2d41d57c 100644 --- a/docs/tutorials/how_to_new_pokemon.md +++ b/docs/tutorials/how_to_new_pokemon.md @@ -1278,3 +1278,26 @@ Gen 4-style shadows are defined by the `SHADOW` macro which takes the following - `SHADOW_SIZE_XL_BATTLE_ONLY` To make the Pokémon have no shadow, use the `NO_SHADOW` macro instead of `SHADOW`. + +## 6. Limiting species allowed as followers +You may use the following configs in `include/config/overworld.h` +```c +#define OW_FOLLOWERS_ALLOWED_SPECIES (0) +#define OW_FOLLOWERS_ALLOWED_MET_LVL (0) +#define OW_FOLLOWERS_ALLOWED_MET_LOC (0) +``` +Examples: +```c +// Yellow Pikachu: +#define OW_FOLLOWERS_ALLOWED_SPECIES (SPECIES_PIKACHU) +#define OW_FOLLOWERS_ALLOWED_MET_LVL (0) +#define OW_FOLLOWERS_ALLOWED_MET_LOC (MAPSEC_PALLET_TOWN) +// Hoenn Starter: +#define OW_FOLLOWERS_ALLOWED_SPECIES (0) +#define OW_FOLLOWERS_ALLOWED_MET_LVL (5) +#define OW_FOLLOWERS_ALLOWED_MET_LOC (MAPSEC_ROUTE_101) +// Species set in VAR_XXXX: +#define OW_FOLLOWERS_ALLOWED_SPECIES (VAR_XXXX) +#define OW_FOLLOWERS_ALLOWED_MET_LVL (0) +#define OW_FOLLOWERS_ALLOWED_MET_LOC (0) +``` From a186ce1bff6760ed8bc4c4aa23456712b1964b45 Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Fri, 11 Apr 2025 13:15:13 +0200 Subject: [PATCH 14/19] Animation fixes from lucky adapted to expansion (#6452) Co-authored-by: Hedara --- data/battle_anim_scripts.s | 368 ++++++++++++++++---------------- src/battle_anim_dragon.c | 36 +++- src/battle_anim_effects_1.c | 12 +- src/battle_anim_effects_2.c | 2 + src/battle_anim_electric.c | 10 +- src/battle_anim_fire.c | 5 + src/battle_anim_flying.c | 5 + src/battle_anim_mon_movement.c | 5 + src/battle_anim_mons.c | 8 + src/battle_anim_normal.c | 4 + src/battle_anim_poison.c | 10 +- src/battle_anim_rock.c | 7 + src/battle_anim_utility_funcs.c | 4 + src/battle_anim_water.c | 11 + 14 files changed, 295 insertions(+), 192 deletions(-) diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index ffc9a930e0..4891c3ef53 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -200,7 +200,7 @@ gBattleAnimMove_NaturalGift:: createvisualtask AnimTask_DragonDanceWaver, 5 playsewithpan SE_M_TELEPORT, -64 delay 8 - createvisualtask AnimTask_BlendPalInAndOutByTag, 5, 10249, 19456, 14, 0, 3 + createvisualtask AnimTask_BlendPalInAndOutByTag, 5, ANIM_TAG_HOLLOW_ORB, 19456, 14, 0, 3 createsprite gDragonDanceOrbSpriteTemplate, ANIM_ATTACKER, 2, 0 createsprite gDragonDanceOrbSpriteTemplate, ANIM_ATTACKER, 2, 43 createsprite gDragonDanceOrbSpriteTemplate, ANIM_ATTACKER, 2, 85 @@ -824,7 +824,7 @@ gBattleAnimMove_Punishment:: monbg ANIM_TARGET setalpha 12, 8 playsewithpan 155, SOUND_PAN_TARGET - createsprite gPunishmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, 1, 0 + createsprite gPunishmentSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 1, 0 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 6, 1 waitforvisualfinish clearmonbg ANIM_TARGET @@ -844,7 +844,7 @@ gBattleAnimMove_Punishment:: gBattleAnimMove_LastResort:: fadetobg BG_COSMIC waitbgfadeout - createvisualtask AnimTask_StartSlidingBg, 2, 4, 0, 128, 0, -1 + createvisualtask AnimTask_StartSlidingBg, 2, 0, 128, 0, -1 waitbgfadein loadspritegfx ANIM_TAG_IMPACT playsewithpan SE_M_SWIFT, SOUND_PAN_ATTACKER @@ -855,19 +855,19 @@ gBattleAnimMove_LastResort:: waitplaysewithpan SE_M_SWAGGER, SOUND_PAN_ATTACKER, 8 createvisualtask AnimTask_TranslateMonEllipticalRespectSide, 2, ANIM_ATTACKER, 18, 6, 2, 4 waitforvisualfinish - createsprite gSimplePaletteBlendSpriteTemplate, ANIM_TARGET, 2, 1, 0, 16, 16, RGB_WHITE - createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, 0, 20, 0, 0, 4 + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 0, 16, 16, RGB_WHITE + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 0, 20, 0, 0, 4 delay 3 waitforvisualfinish playsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 132, -10, 0, 1, 0 createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, 1, -32, 0, 0, 3 waitforvisualfinish - createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_ATTACKER, 0 - createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_TARGET, 0 + createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_ATTACKER, 1 + createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_TARGET, 1 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_ATTACKER, 4, 0, 12, 1 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 4, 0, 12, 1 - createsprite gSimplePaletteBlendSpriteTemplate, ANIM_TARGET, 2, 1, 2, 16, 0, RGB_WHITE + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 2, 16, 0, RGB_WHITE waitforvisualfinish createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_ATTACKER, 1 createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_TARGET, 1 @@ -897,9 +897,9 @@ gBattleAnimMove_SuckerPunch:: loadspritegfx ANIM_TAG_POISON_JAB loadspritegfx ANIM_TAG_IMPACT createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 0, 20, 0, 0, 4 - createsprite gSuckerPunchSpriteTemplate, ANIM_TARGET, 130, -18, 5, 40, 8, 160, 0 + createsprite gSuckerPunchSpriteTemplate, ANIM_TARGET, 2, -18, 5, 40, 8, 160, 0 delay 4 - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 130, -8, 8, 1, 2 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 2, -8, 8, 1, 2 createvisualtask AnimTask_RotateMonSpriteToSide, 2, 6, 384, ANIM_TARGET, 2 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET waitforvisualfinish @@ -1003,11 +1003,11 @@ gBattleAnimGeneral_AquaRingHeal:: createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 12, 0, 25, 0 setalpha 8, 8 playsewithpan SE_M_MILK_DRINK, SOUND_PAN_ATTACKER - createsprite gGuardRingSpriteTemplate, 2, 0 + createsprite gGuardRingSpriteTemplate, ANIM_ATTACKER, 0 delay 4 - createsprite gGuardRingSpriteTemplate, 2, 0 + createsprite gGuardRingSpriteTemplate, ANIM_ATTACKER, 0 delay 4 - createsprite gGuardRingSpriteTemplate, 2, 0 + createsprite gGuardRingSpriteTemplate, ANIM_ATTACKER, 0 waitforvisualfinish playsewithpan SE_SHINY, SOUND_PAN_ATTACKER createvisualtask AnimTask_BlendColorCycle, 2, F_PAL_ATK_SIDE, 0, 2, 0, 10, RGB_WHITE @@ -1090,33 +1090,33 @@ gBattleAnimMove_FlareBlitz:: createvisualtask AnimTask_ShakeMon2, 2, ANIM_TARGET, 4, 0, 22, 1 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 0, 0, 1, 0 - createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, 192, 176, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 1, 0, 10, 192, 176, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 24, 8, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, -192, 240, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 1, 0, 10, -192, 240, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, -24, -16, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, 192, -160, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 1, 0, 10, 192, -160, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 8, 4, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, -192, -112, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 1, 0, 10, -192, -112, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, -16, 19, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, 160, 48, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 1, 0, 10, 160, 48, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 18, -18, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, -224, -32, 40 - createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, 112, -128, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 1, 0, 10, -224, -32, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 1, 0, 10, 112, -128, 40 playsewithpan SE_M_COMET_PUNCH, +63 createvisualtask AnimTask_BlendBattleAnimPal, 10, 4, 2, 0, 0, RGB_BLACK playsewithpan SE_M_COMET_PUNCH, +63 @@ -1138,10 +1138,10 @@ gBattleAnimMove_ForcePalm:: splitbgprio ANIM_TARGET setalpha 12, 8 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_TARGET - createsprite gKarateChopSpriteTemplate, ANIM_TARGET, 2, -16, 0, 0, 0, 10, 1, 3, 0 + createsprite gKarateChopSpriteTemplate, ANIM_ATTACKER, 2, -16, 0, 0, 0, 10, 1, 3, 0 waitforvisualfinish playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET - createsprite gForcePalmSpriteTemplate, ANIM_TARGET 3, 0, 0, 1, 2 + createsprite gForcePalmSpriteTemplate, ANIM_ATTACKER 3, 0, 0, 1, 2 createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 4, 0, 6, 1 waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -1379,17 +1379,17 @@ gBattleAnimMove_AquaTail:: createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 6 delay 4 playsewithpan SE_M_VITAL_THROW, SOUND_PAN_TARGET - createsprite gAquaTailKnockOffSpriteTemplate, ANIM_ATTACKER, 130, -16, -16 + createsprite gAquaTailKnockOffSpriteTemplate, ANIM_ATTACKER, 2, -16, -16 delay 8 - createsprite gComplexPaletteBlendSpriteTemplate, ANIM_TARGET, 2, 31, 5, 1, RGB_WHITE, 10, 0, 0 - createsprite gAquaTailHitSpriteTemplate, ANIM_TARGET, 131, 0, 0, 1, 2 + createsprite gComplexPaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 31, 5, 1, RGB_WHITE, 10, 0, 0 + createsprite gAquaTailHitSpriteTemplate, ANIM_TARGET, 3, 0, 0, 1, 2 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET - createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, ANIM_TARGET, -12, 10, 0, 3 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, -12, 10, 0, 3 createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, ANIM_ATTACKER, 0, 5 delay 3 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 0, 3, 6, 1 delay 5 - createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_TARGET, 2, ANIM_TARGET, 0, 6 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 0, 6 delay 10 waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -1532,7 +1532,7 @@ gBattleAnimMove_DragonPulse:: clearmonbg ANIM_TARGET end DragonPulseParticle: - createsprite gDragonPulseSpriteTemplate, ANIM_ATTACKER, 130, 16, 0, 0, 0, 13, 0 + createsprite gDragonPulseSpriteTemplate, ANIM_TARGET, 2, 16, 0, 0, 0, 13, 0 delay 4 return @@ -1544,21 +1544,21 @@ gBattleAnimMove_DragonRush:: createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 6 delay 4 playsewithpan SE_M_VITAL_THROW, SOUND_PAN_TARGET - createsprite gDragonRushSpriteTemplate, ANIM_ATTACKER, 131, -16, -16 + createsprite gDragonRushSpriteTemplate, ANIM_ATTACKER, 3, -16, -16 delay 8 - createsprite gComplexPaletteBlendSpriteTemplate, ANIM_TARGET, 2, 31, 5, 1, RGB_WHITE, 10, 0, 0 - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, 0, 0, 1, 1 + createsprite gComplexPaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 31, 5, 1, RGB_WHITE, 10, 0, 0 + createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 0, 0, 1, 1 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 0, 5, 1 waitforvisualfinish playsewithpan 131, SOUND_PAN_TARGET - createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, 20, 24, 14, 2 - createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 5, 0, -20, 24, 14, 1 - createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 5, 20, -24, 14, 2 - createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, -5, 0, 20, 24, 14, 2 - createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, -5, 30, 18, 8, 2 - createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, 30, -18, 8, 2 - createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, -30, 18, 8, 2 - createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, -30, -18, 8, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 20, 24, 14, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_ATTACKER, 2, 5, 0, -20, 24, 14, 1 + createsprite gRockFragmentSpriteTemplate, ANIM_ATTACKER, 2, 0, 5, 20, -24, 14, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_ATTACKER, 2, -5, 0, 20, 24, 14, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_ATTACKER, 2, 0, -5, 30, 18, 8, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 30, -18, 8, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, -30, 18, 8, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, -30, -18, 8, 2 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 0, 3, 7, 1 waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -1704,29 +1704,28 @@ gBattleAnimMove_BraveBird:: gBattleAnimMove_EarthPower:: loadspritegfx ANIM_TAG_SMALL_EMBER loadspritegfx ANIM_TAG_FIRE_PLUME - createvisualtask AnimTask_HorizontalShake, 3, ANIM_DEF_PARTNER, 10, 50 createvisualtask AnimTask_HorizontalShake, 3, ANIM_TARGET, 10, 50 playsewithpan SE_M_EARTHQUAKE, SOUND_PAN_TARGET delay 40 loopsewithpan 145, SOUND_PAN_TARGET 11, 3 createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 3, 25, 1 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, 5, 0 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 66, 1, 5, 0 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, -10, -15 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 66, 1, -10, -15 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 130, 1, 0, 25 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 2, 1, 0, 25 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, 15, 5 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 66, 1, 15, 5 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, -25, 0 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 66, 1, -25, 0 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 130, 1, 30, 30 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 2, 1, 30, 30 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 130, 1, -27, 25 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 2, 1, -27, 25 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, 0, 8 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 66, 1, 0, 8 waitforvisualfinish - createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_TARGET, 194, 0, 0, 4 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_TARGET, 66, 0, 0, 4 waitforvisualfinish end @@ -1790,7 +1789,7 @@ GigaImpactContinuity: createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 4, -10, 0, 1, 0 playsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET delay 1 - createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, 1, -16, 0, 0, 4 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 1, -16, 0, 0, 4 waitforvisualfinish createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 4, 0, 12, 1 waitforvisualfinish @@ -1879,17 +1878,17 @@ gBattleAnimMove_Avalanche:: loadspritegfx ANIM_TAG_ROCKS loadspritegfx ANIM_TAG_ICE_CHUNK monbg ANIM_DEF_PARTNER - createsprite gShakeMonOrTerrainSpriteTemplate, ANIM_TARGET, 2, 7, 1, 11, 1 - createsprite gAvalancheSpriteTemplate, ANIM_TARGET, 130, -5, 1, -5, 1 + createsprite gShakeMonOrTerrainSpriteTemplate, ANIM_ATTACKER, 2, 7, 1, 11, 1 + createsprite gAvalancheSpriteTemplate, ANIM_TARGET, 2, -5, 1, -5, 1 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET delay 2 - createsprite gAvalancheSpriteTemplate, ANIM_TARGET, 130, 5, 0, 6, 1 + createsprite gAvalancheSpriteTemplate, ANIM_TARGET, 2, 5, 0, 6, 1 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET delay 2 - createsprite gAvalancheSpriteTemplate, ANIM_TARGET, 130, 19, 1, 10, 1 + createsprite gAvalancheSpriteTemplate, ANIM_TARGET, 2, 19, 1, 10, 1 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET delay 2 - createsprite gAvalancheSpriteTemplate ANIM_TARGET, 130, -17, 2, -20, 1 + createsprite gAvalancheSpriteTemplate ANIM_TARGET, 2, -17, 2, -20, 1 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 0, 5, 50, 1 createvisualtask AnimTask_ShakeMon, 2, ANIM_DEF_PARTNER, 0, 5, 50, 1 @@ -2212,7 +2211,7 @@ gBattleAnimMove_ZenHeadbutt:: setalpha 12, 8 createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 2, 0, 4, 0 waitforvisualfinish - createsprite gZenHeadbuttSpriteTemplate, ANIM_ATTACKER, 66, 0 + createsprite gZenHeadbuttSpriteTemplate, ANIM_ATTACKER, 2, 0 delay 18 playsewithpan SE_M_MORNING_SUN, SOUND_PAN_ATTACKER waitforvisualfinish @@ -2228,7 +2227,7 @@ gBattleAnimMove_ZenHeadbutt:: createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_ATTACKER, 2, 0, 4, 1 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 5, 0, 6, 1 createsprite gBowMonSpriteTemplate, ANIM_ATTACKER, 1, 2 - createsprite gAquaTailHitSpriteTemplate, ANIM_TARGET, 131, 0, 0, 1, 1 + createsprite gAquaTailHitSpriteTemplate, ANIM_TARGET, 3, 0, 0, 1, 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET waitforvisualfinish createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 4, 4, 0, 0 @@ -2246,22 +2245,22 @@ gBattleAnimMove_MirrorShot:: createvisualtask AnimTask_BlendBattleAnimPalExclude, 5, 5, 2, 0, 10, RGB_WHITEALPHA createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_IMPACT, 0, 12, 12, RGB(21, 21, 21) waitforvisualfinish - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET waitforvisualfinish createvisualtask AnimTask_BlendBattleAnimPalExclude, 5, 5, 2, 10, 0, RGB_WHITEALPHA @@ -2318,27 +2317,27 @@ gBattleAnimMove_RockClimb:: monbg ANIM_DEF_PARTNER splitbgprio ANIM_TARGET setalpha 12, 8 - createvisualtask AnimTask_Rollout, 2, 0 + createvisualtask AnimTask_Rollout, 2, 1 waitforvisualfinish - createvisualtask AnimTask_ShakeTargetBasedOnMovePowerOrDmg, 2, 0, 1, 30, 1, RGB(0, 16, 1) - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, -15, 8, 1, 1 + createvisualtask AnimTask_ShakeTargetBasedOnMovePowerOrDmg, 2, 0, 1, 30, 1, 0 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, -15, 8, 1, 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, -5, -12, 1, 1 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, -5, -12, 1, 1 delay 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 0, -32, 1, 1 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, 0, -32, 1, 1 delay 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 5, -52, 1, 1 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, 5, -52, 1, 1 createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, 1, -25, 16, 1, 4 delay 4 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 0, 3, 6, 1 delay 30 createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 6 delay 4 - createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_TARGET, 2, 1, 0, 6 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, 1, 0, 6 clearmonbg ANIM_DEF_PARTNER blendoff end @@ -2435,32 +2434,32 @@ gBattleAnimMove_DracoMeteor:: blendoff end DracoMeteor1: - createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 131, -48, -64, 40, 32, 25 + createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 3, -48, -64, 40, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -48, -64, 40, 32, 25 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 3, -48, -64, 40, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -48, -64, 40, 32, 25 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 3, -48, -64, 40, 32, 25 return DracoMeteor2: - createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 131, -112, -64, -8, 32, 25 + createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 3, -112, -64, -8, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -112, -64, -8, 32, 25 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 3, -112, -64, -8, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -112, -64, -8, 32, 25 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 3, -112, -64, -8, 32, 25 return DracoMeteor3: - createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, 24, 32, 25 + createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 3, -80, -64, 24, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, 24, 32, 25 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 3, -80, -64, 24, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, 24, 32, 25 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 3, -80, -64, 24, 32, 25 return DracoMeteor4: - createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, -8, 32, 25 + createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 3, -80, -64, -8, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, -8, 32, 25 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 3, -80, -64, -8, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, -8, 32, 25 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 3, -80, -64, -8, 32, 25 return gBattleAnimMove_Discharge:: @@ -2576,14 +2575,14 @@ gBattleAnimMove_LavaPlume:: createvisualtask AnimTask_ShakeMon2, 2, ANIM_DEF_PARTNER, 1, 0, 32, 1 createvisualtask AnimTask_ShakeMon2, 2, ANIM_ATK_PARTNER, 1, 0, 32, 1 waitforvisualfinish - createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 0 - createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 32 - createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 64 - createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 96 - createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 128 - createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 160 - createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 192 - createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 224 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 2, 0 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 2, 32 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 2, 64 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 2, 96 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 2, 128 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 2, 160 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 2, 192 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 2, 224 playsewithpan SE_M_SACRED_FIRE, SOUND_PAN_ATTACKER waitforvisualfinish end @@ -2729,7 +2728,7 @@ RockWrecker_1: createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 6 delay 3 playsewithpan SE_M_SWAGGER, SOUND_PAN_ATTACKER - createsprite gRockBlastRockSpriteTemplate, ANIM_ATTACKER, 130, 16, 0, 0, 0, 25, 257 + createsprite gRockBlastRockSpriteTemplate, ANIM_ATTACKER, 130, 16, 0, 0, 0, 25, (1 << 8) | 1 waitforvisualfinish createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 0, 0, 1, 1 playsewithpan SE_M_ROCK_THROW SOUND_PAN_TARGET @@ -2747,15 +2746,15 @@ RockWrecker_2: createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 6 delay 3 playsewithpan SE_M_SWAGGER, SOUND_PAN_ATTACKER - createsprite gRockBlastRockSpriteTemplate, ANIM_ATTACKER, 130, 16, 0, 0, 0, 25, 257 + createsprite gRockBlastRockSpriteTemplate, ANIM_ATTACKER, 2, 16, 0, 0, 0, 25, 257 waitforvisualfinish - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 0, 0, 1, 1 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, 0, 0, 1, 1 playsewithpan SE_M_ROCK_THROW SOUND_PAN_TARGET - createsprite gRockFragmentSpriteTemplate ANIM_TARGET, 130, 0, 0, 20, 24, 14, 2 + createsprite gRockFragmentSpriteTemplate ANIM_TARGET, 2, 0, 0, 20, 24, 14, 2 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 5, 1 - createsprite gRockFragmentSpriteTemplate ANIM_ATTACKER, 130, 5, 0, -20, 24, 14, 1 - createsprite gRockFragmentSpriteTemplate ANIM_ATTACKER, 130, 0, 5, 20, -18, 14, 2 - createsprite gRockFragmentSpriteTemplate ANIM_ATTACKER, 130, -5, 0, -20, -18, 14, 2 + createsprite gRockFragmentSpriteTemplate ANIM_ATTACKER, 2, 5, 0, -20, 24, 14, 1 + createsprite gRockFragmentSpriteTemplate ANIM_ATTACKER, 2, 0, 5, 20, -18, 14, 2 + createsprite gRockFragmentSpriteTemplate ANIM_ATTACKER, 2, -5, 0, -20, -18, 14, 2 waitforvisualfinish call UnsetPsychicBg end @@ -2788,7 +2787,7 @@ gBattleAnimMove_GunkShot:: createvisualtask AnimTask_ShakeMon, 5, ANIM_ATTACKER, 0, 2, 40, 1 delay 6 panse SE_M_HYDRO_PUMP, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 2, 0 - createvisualtask AnimTask_StartSinAnimTimer, 5, 1, 100 + createvisualtask AnimTask_StartSinAnimTimer, 5, 100 call GunkShotParticles call GunkShotParticles call GunkShotParticles @@ -2860,7 +2859,7 @@ gBattleAnimMove_MagnetBomb:: loadspritegfx ANIM_TAG_SPARK_2 delay 0 playsewithpan 119, 192 - createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 32, 24, 190, 12, 0, 1, 0 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 32, 24, 190, 12, 0, 1, 0 delay 0 createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 80, 24, 22, 12, 0, 1, 0 createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 156, 24, 121, 13, 0, 1, 1 @@ -2901,22 +2900,22 @@ gBattleAnimMove_MagnetBomb:: loadspritegfx ANIM_TAG_GRAY_SMOKE loadspritegfx ANIM_TAG_BLACK_BALL playsewithpan 177, 63 - createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, 8, 8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 2, 8, 8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, -8, -8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 2, -8, -8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, 8, -8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 2, 8, -8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, -8, 8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 2, -8, 8, 1, 0 waitforvisualfinish playsewithpan 177, 63 - createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, 8, 8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 2, 8, 8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, -8, -8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 2, -8, -8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, 8, -8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 2, 8, -8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, -8, 8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 2, -8, 8, 1, 0 waitforvisualfinish end @@ -2924,55 +2923,54 @@ gBattleAnimMove_StoneEdge:: loadspritegfx ANIM_TAG_STONE_EDGE loadspritegfx ANIM_TAG_IMPACT playsewithpan SE_M_ROCK_THROW SOUND_PAN_TARGET - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 528, 30, 13, 50, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 28, 528, 30, 13, 50, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 32, 480, 20, 16, -46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 32, 480, 20, 16, -46, 1 delay 2 loopsewithpan 131, SOUND_PAN_TARGET 24, 3 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 576, 20, 8, 42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 33, 576, 20, 8, 42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 31, 400, 25, 11, -42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 31, 400, 25, 11, -42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 512, 25, 16, 46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 28, 512, 25, 16, 46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 464, 30, 15, 49, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 33, 464, 30, 15, 49, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 528, 30, 13, 50, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 28, 528, 30, 13, 50, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 32, 480, 20, 16, -46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 32, 480, 20, 16, -46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 576, 20, 8, 42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 33, 576, 20, 8, 42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 31, 400, 25, 11, -42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 31, 400, 25, 11, -42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 512, 25, 16, 46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 28, 512, 25, 16, 46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 464, 30, 15, 49, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 33, 464, 30, 15, 49, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 528, 30, 13, 50, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 28, 528, 30, 13, 50, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 32, 480, 20, 16, -46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 32, 480, 20, 16, -46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 576, 20, 8, 42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 33, 576, 20, 8, 42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 31, 400, 25, 11, -42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 31, 400, 25, 11, -42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 512, 25, 16, 46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 28, 512, 25, 16, 46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 464, 30, 15, 49, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 2, 0, 33, 464, 30, 15, 49, 1 delay 2 - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, -32, -16, 1, 3 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, -32, -16, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 3, 0, 12, 1 - createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_DEF_PARTNER, 3, 0, 12, 1 delay 4 - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 3 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 4 - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 3 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 4 - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 32, 20, 1, 3 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, 32, 20, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -3016,9 +3014,9 @@ gBattleAnimMove_GrassKnot:: loadspritegfx ANIM_TAG_RAZOR_LEAF loadspritegfx ANIM_TAG_IMPACT createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 0, 20, 0, 0, 4 - createsprite gGrassKnotSpriteTemplate, ANIM_TARGET, 130, -18, 19, 40, 8, 160, 0 + createsprite gGrassKnotSpriteTemplate, ANIM_TARGET, 2, -18, 19, 40, 8, 160, 0 delay 4 - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 130, -8, 8, 1, 2 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 2, -8, 8, 1, 2 createvisualtask AnimTask_RotateMonSpriteToSide, 2, 6, 384, ANIM_TARGET, 2 playsewithpan SE_M_VITAL_THROW2 SOUND_PAN_TARGET waitforvisualfinish @@ -3287,6 +3285,7 @@ gBattleAnimMove_AquaJet:: loadspritegfx ANIM_TAG_SPARKLE_6 loadspritegfx ANIM_TAG_ROUND_SHADOW loadspritegfx ANIM_TAG_SPLASH + loadspritegfx ANIM_TAG_SWEAT_BEAD playsewithpan SE_M_HEADBUTT, SOUND_PAN_ATTACKER createsprite gDiveBallSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 13, 336 waitforvisualfinish @@ -3302,7 +3301,7 @@ gBattleAnimMove_AquaJet:: monbg ANIM_DEF_PARTNER setalpha 12, 8 playsewithpan SE_M_EXPLOSION, SOUND_PAN_TARGET - createsprite gDiveWaterSplashSpriteTemplate, ANIM_TARGET, 131, 1 + createsprite gDiveWaterSplashSpriteTemplate, ANIM_TARGET, 3, 1 call DiveAttackWaterDroplets call DiveAttackWaterDroplets call DiveAttackWaterDroplets @@ -3323,39 +3322,39 @@ gBattleAnimMove_AttackOrder:: monbg ANIM_DEF_PARTNER splitbgprio ANIM_TARGET playsewithpan SE_M_SWEET_SCENT, SOUND_PAN_TARGET - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 120, 70, 5, 70, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 120, 70, 5, 70, 30 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 120, 55, 6, 60, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 120, 55, 6, 60, 25 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 120, 60, 7, 60, 30 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 120, 55, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 120, 60, 7, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 120, 55, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 100, 50, 4, 50, 26 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 100, 50, 4, 50, 26 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 105, 25, 8, 60, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 105, 25, 8, 60, 20 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 120, 40, 10, 48, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 120, 40, 10, 48, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 120, 30, 6, 45, 25 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 120, 35, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 120, 30, 6, 45, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 120, 35, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 105, 20, 8, 40, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 105, 20, 8, 40, 0 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 20, 255, 15, 32, 0 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 110, 10, 8, 32, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 20, 255, 15, 32, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 110, 10, 8, 32, 20 waitforvisualfinish - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, -32, -16, 1, 3 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, -32, -16, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 3, 0, 12, 1 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 3, 0, 12, 1 delay 4 - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 3 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 4 - createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 3 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 4 - createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 32, 20, 1, 3 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, 32, 20, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -3369,30 +3368,30 @@ gBattleAnimMove_DefendOrder:: monbg ANIM_DEF_PARTNER splitbgprio ANIM_TARGET playsewithpan SE_M_SWEET_SCENT, SOUND_PAN_TARGET - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 120, 70, 5, 70, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 120, 70, 5, 70, 30 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 55, 6, 60, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 115, 55, 6, 60, 25 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 60, 7, 60, 30 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 55, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 115, 60, 7, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 115, 55, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 100, 50, 4, 50, 26 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 100, 50, 4, 50, 26 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 105, 25, 8, 60, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 105, 25, 8, 60, 20 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 40, 10, 48, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 115, 40, 10, 48, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 120, 30, 6, 45, 25 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 35, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 120, 30, 6, 45, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 115, 35, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 105, 20, 8, 40, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 105, 20, 8, 40, 0 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 20, 255, 15, 32, 0 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 110, 10, 8, 32, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 20, 255, 15, 32, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 2, 110, 10, 8, 32, 20 waitforvisualfinish loadspritegfx ANIM_TAG_BLUE_STAR waitforvisualfinish - clearmonbg ANIM_ATK_PARTNER + clearmonbg ANIM_DEF_PARTNER blendoff delay 1 call BideSetUp @@ -3406,30 +3405,30 @@ gBattleAnimMove_HealOrder:: monbg ANIM_DEF_PARTNER splitbgprio ANIM_TARGET playsewithpan SE_M_SWEET_SCENT, SOUND_PAN_TARGET - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 120, 70, 5, 70, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 120, 70, 5, 70, 30 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 55, 6, 60, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 115, 55, 6, 60, 25 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 60, 7, 60, 30 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 55, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 115, 60, 7, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 115, 55, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 100, 50, 4, 50, 26 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 100, 50, 4, 50, 26 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 105, 25, 8, 60, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 105, 25, 8, 60, 20 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 40, 10, 48, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 115, 40, 10, 48, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 120, 30, 6, 45, 25 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 35, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 120, 30, 6, 45, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 115, 35, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 105, 20, 8, 40, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 105, 20, 8, 40, 0 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 20, 255, 15, 32, 0 - createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 110, 10, 8, 32, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 20, 255, 15, 32, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 2, 110, 10, 8, 32, 20 waitforvisualfinish loadspritegfx ANIM_TAG_BLUE_STAR waitforvisualfinish - clearmonbg ANIM_ATK_PARTNER + clearmonbg ANIM_DEF_PARTNER blendoff delay 1 call HealingEffect @@ -3469,6 +3468,10 @@ gBattleAnimMove_DoubleHit:: playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 8 waitforvisualfinish + @ why does the anim hit twice? + @ that just means the anim plays 4 times + @ which doesn't make sense + @ I don't know, but I'm not gonna argue with it createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 4 delay 6 createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 2, 0, 0, 1, 2 @@ -3560,7 +3563,7 @@ gBattleAnimMove_LunarDance:: loadspritegfx ANIM_TAG_GREEN_SPARKLE loadspritegfx ANIM_TAG_HOLLOW_ORB setalpha 0, 16 - createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 1, 0, 16, 0 + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 1, 0, 16, RGB_BLACK waitforvisualfinish createsprite gMoonSpriteTemplate, ANIM_ATTACKER, 2, 120, 56 createvisualtask AnimTask_AlphaFadeIn, 3, 0, 16, 16, 0, 1 @@ -3576,8 +3579,8 @@ gBattleAnimMove_LunarDance:: delay 30 createsprite gMoonlightSparkleSpriteTemplate, ANIM_ATTACKER, 40, 10, 0 delay 20 - createvisualtask AnimTask_MoonlightEndFade, 2, 0 - createvisualtask AnimTask_DragonDanceWaver, 5, 0 + createvisualtask AnimTask_MoonlightEndFade, 2 + createvisualtask AnimTask_DragonDanceWaver, 5 playsewithpan 203, SOUND_PAN_ATTACKER delay 8 createvisualtask AnimTask_BlendPalInAndOutByTag, 5, ANIM_TAG_HOLLOW_ORB, RGB(0, 0, 19), 14, 0, 3 @@ -3592,7 +3595,6 @@ gBattleAnimMove_LunarDance:: delay 30 playsewithpan 203, SOUND_PAN_ATTACKER waitforvisualfinish - clearmonbg ANIM_ATTACKER delay 1 end @@ -3640,7 +3642,7 @@ gBattleAnimMove_MagmaStorm:: call FireSpinEffect restorebg waitbgfadeout - setarg 7, 0xFFF + setarg 7, 0xFFFF waitbgfadein clearmonbg ANIM_DEF_PARTNER blendoff @@ -3769,7 +3771,7 @@ gBattleAnimMove_OminousWind:: delay 0 createvisualtask AnimTask_BlendBattleAnimPalExclude, 10, 1, 0, 0, 0, 0 delay 0 - createvisualtask AnimTask_GetAttackerSide, 2, 0 + createvisualtask AnimTask_GetAttackerSide, 2 jumpargeq 7, 1, OminousWindFadeToBg fadetobg BG_GHOST waitbgfadeout @@ -21118,7 +21120,7 @@ gBattleAnimMove_Rollout:: monbg ANIM_DEF_PARTNER splitbgprio ANIM_TARGET setalpha 12, 8 - createvisualtask AnimTask_Rollout, 2 + createvisualtask AnimTask_Rollout, 2, 0 waitforvisualfinish createvisualtask AnimTask_ShakeTargetBasedOnMovePowerOrDmg, 2, FALSE, 1, 30, 1, 0 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 4, 0, 0, ANIM_TARGET, 2 @@ -28311,7 +28313,7 @@ Status_MagmaStorm: call FireSpinEffect restorebg waitbgfadeout - setarg 7, 0xFFF + setarg 7, 0xFFFF waitbgfadein stopsound clearmonbg ANIM_DEF_PARTNER diff --git a/src/battle_anim_dragon.c b/src/battle_anim_dragon.c index 55ecd5d0c1..bf5c4d823c 100644 --- a/src/battle_anim_dragon.c +++ b/src/battle_anim_dragon.c @@ -9,6 +9,7 @@ static void AnimDragonDanceOrb_Step(struct Sprite *); static void AnimOverheatFlame_Step(struct Sprite *); static void AnimTask_DragonDanceWaver_Step(u8); static void UpdateDragonDanceScanlineEffect(struct Task *); +static void AnimDragonRush(struct Sprite *sprite); static void AnimDragonRushStep(struct Sprite *sprite); static void AnimSpinningDracoMeteor(struct Sprite *sprite); static void AnimSpinningDracoMeteorFinish(struct Sprite *sprite); @@ -304,7 +305,7 @@ const struct SpriteTemplate gDragonRushSpriteTemplate = .anims = gDragonRushAnimTable, .images = NULL, .affineAnims = gDragonRushAffineAnimTable, - .callback = AnimDragonRushStep, + .callback = AnimDragonRush, }; const struct SpriteTemplate gDracoMetorSpriteTemplate = @@ -329,6 +330,36 @@ const struct SpriteTemplate gDragonPulseSpriteTemplate = .callback = TranslateAnimSpriteToTargetMonLocation, }; +// Animates a strike that swipes downard at the target mon. +// arg 0: initial x pixel offset +// arg 1: initial y pixel offset +static void AnimDragonRush(struct Sprite *sprite) +{ + if (GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER) + { + sprite->x -= gBattleAnimArgs[0]; + sprite->y += gBattleAnimArgs[1]; + sprite->data[0] = -11; + sprite->data[1] = 192; + StartSpriteAffineAnim(sprite, 1); + } + else + { + sprite->data[0] = 11; + sprite->data[1] = 192; + sprite->x += gBattleAnimArgs[0]; + sprite->y += gBattleAnimArgs[1]; + } + + sprite->callback = AnimDragonRushStep; +} + +// args[0] - initial x delta +// args[1] - initial y delta +// args[2] - x delta to end x +// args[3] - y delta to end y +// args[4] - num frames +// args[5] - sprite anim number static void AnimDragonRushStep(struct Sprite *sprite) { // These two cases are identical. @@ -422,6 +453,9 @@ static void StartDragonFireTranslation(struct Sprite *sprite) StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix); } +// args[0] - attacker or target +// args[1] - initial x offset +// args[2] - initial y offset void AnimDragonRageFirePlume(struct Sprite *sprite) { if (gBattleAnimArgs[0] == 0) diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index 4162447094..8e1e39d629 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -3116,6 +3116,12 @@ const struct SpriteTemplate gChainBindingSpriteTemplate = }; // functions +// args[0] - initial x offset +// args[1] - initial y offset +// args[2] - some param to linear translation +// args[3] - some param to linear translation +// args[4] - offset that gets added to param for Sin +// args[5] - another param for Sin static void AnimGrassKnot(struct Sprite *sprite) { if (BATTLE_PARTNER(gBattleAnimAttacker) == gBattleAnimTarget && GetBattlerPosition(gBattleAnimTarget) < B_POSITION_PLAYER_RIGHT) @@ -5972,12 +5978,12 @@ static void AnimBowMon_Step1_Callback(struct Sprite *sprite) { sprite->data[3] = gBattlerSpriteIds[gBattleAnimAttacker]; PrepareBattlerSpriteForRotScale(sprite->data[3], ST_OAM_OBJ_NORMAL); - sprite->data[4] = (sprite->data[6] = GetBattlerSide(gBattleAnimAttacker)) ? 0x300 : 0xFFFFFD00; + sprite->data[4] = (sprite->data[6] = GetBattlerSide(gBattleAnimAttacker)) ? 768 : -768; sprite->data[5] = 0; } sprite->data[5] += sprite->data[4]; - SetSpriteRotScale(sprite->data[3], 0x100, 0x100, sprite->data[5]); + SetSpriteRotScale(sprite->data[3], 256, 256, sprite->data[5]); SetBattlerSpriteYOffsetFromRotation(sprite->data[3]); if (++sprite->data[0] > 3) { @@ -6463,6 +6469,8 @@ static void UNUSED AnimTask_ShowBattlersHealthbox(u8 taskId) DestroyAnimVisualTask(taskId); } +// args[0] - sprite x +// args[1] - sprite y static void AnimMoon(struct Sprite *sprite) { if (IsContest()) diff --git a/src/battle_anim_effects_2.c b/src/battle_anim_effects_2.c index e751a1ca51..c4d0a33fac 100755 --- a/src/battle_anim_effects_2.c +++ b/src/battle_anim_effects_2.c @@ -3133,6 +3133,8 @@ static void AnimHealBellMusicNote(struct Sprite *sprite) SetMusicNotePalette(sprite, gBattleAnimArgs[5], gBattleAnimArgs[6]); } +// args[0] - initial x offset +// args[1] - initial y offset void AnimMagentaHeart(struct Sprite *sprite) { if (++sprite->data[0] == 1) diff --git a/src/battle_anim_electric.c b/src/battle_anim_electric.c index 59cd017b9a..bd010797a1 100644 --- a/src/battle_anim_electric.c +++ b/src/battle_anim_electric.c @@ -657,13 +657,13 @@ static void AnimUnusedCirclingShock(struct Sprite *sprite) sprite->callback = TranslateSpriteInCircle; } -// arg 0: -// arg 1: -// arg 2: +// arg 0: index to sine table +// arg 1: something multiplied with +// arg 2: index to sine table // arg 3: duration // arg 4: target -// arg 5: -// arg 6: +// arg 5: 0 or non-0 determines which set of battler sprite coords to use +// arg 6: increase battler sprite priority by 1 void AnimSparkElectricity(struct Sprite *sprite) { u8 battler; diff --git a/src/battle_anim_fire.c b/src/battle_anim_fire.c index b67304e05e..7f89fb7d1d 100644 --- a/src/battle_anim_fire.c +++ b/src/battle_anim_fire.c @@ -572,6 +572,11 @@ static void AnimFireSpiralInward(struct Sprite *sprite) } // For the impact spread of fire sprites for moves like Blaze Kick or Fire Punch +// args[0] - delta to mon x offset +// args[1] - delta to mon y offset +// args[2] - x increment +// args[3] - y increment +// args[4] - duration void AnimFireSpread(struct Sprite *sprite) { SetAnimSpriteInitialXOffset(sprite, gBattleAnimArgs[0]); diff --git a/src/battle_anim_flying.c b/src/battle_anim_flying.c index 8b613ad677..a4b37389ed 100644 --- a/src/battle_anim_flying.c +++ b/src/battle_anim_flying.c @@ -1027,6 +1027,10 @@ void AnimBounceBallLand(struct Sprite *sprite) } } +// args[0] - initial x offset +// args[1] - initial y offset +// args[2] - initial delay before anim +// args[3] - quadratic delta to sprite y static void AnimDiveBall(struct Sprite *sprite) { InitSpritePosToAnimAttacker(sprite, TRUE); @@ -1066,6 +1070,7 @@ static void AnimDiveBall_Step2(struct Sprite *sprite) DestroyAnimSprite(sprite); } +// args[0] - attacker or target static void AnimDiveWaterSplash(struct Sprite *sprite) { u32 matrixNum; diff --git a/src/battle_anim_mon_movement.c b/src/battle_anim_mon_movement.c index 0bacd96219..e8ce92677c 100644 --- a/src/battle_anim_mon_movement.c +++ b/src/battle_anim_mon_movement.c @@ -1173,6 +1173,11 @@ void SetupShakeBattlerBasedOnMovePowerOrDmg(u8 taskId, u8 animBattlerId) gTasks[taskId].data[2] = gBattleAnimArgs[2]; } +// args[0] - 0 if scale on move power, 1 if scale on move damage +// args[1] - delay before starting anim +// args[2] - duration of anim (after anim starts from above counter) +// args[3] - 1 if do horizontal shake +// args[4] - 1 if do vertical shake void AnimTask_ShakeTargetPartnerBasedOnMovePowerOrDmg(u8 taskId) { SetupShakeBattlerBasedOnMovePowerOrDmg(taskId, ANIM_DEF_PARTNER); diff --git a/src/battle_anim_mons.c b/src/battle_anim_mons.c index 13b1cf834f..af38afc814 100644 --- a/src/battle_anim_mons.c +++ b/src/battle_anim_mons.c @@ -1429,6 +1429,9 @@ static u8 UNUSED GetSpritePalIdxByPosition(u8 position) return GetBattlerAtPosition(position); } +// gBattleAnimArgs 0-3 used +// 0, 1 used for position +// 2, 3 as some control variables void AnimSpriteOnMonPos(struct Sprite *sprite) { bool8 var; @@ -1698,6 +1701,11 @@ static void AnimTask_BlendMonInAndOut_Step(u8 taskId) } // See AnimTask_BlendMonInAndOut. Same, but ANIM_TAG_* instead of mon +// args[0] - tag +// arg 1: blend color +// arg 2: target blend coefficient +// arg 3: initial delay +// arg 4: number of times to blend in and out void AnimTask_BlendPalInAndOutByTag(u8 task) { u8 palette = IndexOfSpritePaletteTag(gBattleAnimArgs[0]); diff --git a/src/battle_anim_normal.c b/src/battle_anim_normal.c index d9fc8aa412..a8a6417d6e 100644 --- a/src/battle_anim_normal.c +++ b/src/battle_anim_normal.c @@ -1045,6 +1045,10 @@ static void AnimTask_ShakeBattleTerrain_Step(u8 taskId) #undef tTimer #undef tShakeDelay +// args[0] - initial pos x +// args[1] - initial pos y +// args[2] - which battler +// args[3] - affine anim number void AnimHitSplatBasic(struct Sprite *sprite) { StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]); diff --git a/src/battle_anim_poison.c b/src/battle_anim_poison.c index 301cdd4643..a75ce87087 100644 --- a/src/battle_anim_poison.c +++ b/src/battle_anim_poison.c @@ -415,11 +415,15 @@ const struct SpriteTemplate gSyrupBombYellowShellBSpriteTemplate = .callback = AnimAnimSyrupBomb, }; +// args[0] - initial x +// args[1] - initial y +// args[2] - attacker or target +// args[3] - affine anim number static void AnimGunkShotImpact(struct Sprite *sprite) { StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]); if (gBattleAnimArgs[2] == 0) - InitSpritePosToAnimAttacker(sprite, 1); + InitSpritePosToAnimAttacker(sprite, TRUE); else InitSpritePosToAnimTarget(sprite, TRUE); @@ -427,6 +431,10 @@ static void AnimGunkShotImpact(struct Sprite *sprite) StoreSpriteCallbackInData6(sprite, DestroyAnimSprite); } +// args[0] - initial attacker x +// args[1] - initial attacker y +// args[2] - ??? +// args[3] - some param static void AnimGunkShotParticles(struct Sprite *sprite) { u16 retArg; diff --git a/src/battle_anim_rock.c b/src/battle_anim_rock.c index 0aaf5f1609..dcdb2a8965 100644 --- a/src/battle_anim_rock.c +++ b/src/battle_anim_rock.c @@ -476,6 +476,13 @@ void AnimRockFragment(struct Sprite *sprite) } // Swirls particle in vortex. Used for moves like Fire Spin or Sand Tomb +// args[0] - initial x offset +// args[1] - initial y offset +// args[2] - y increment +// args[3] - duration +// args[4] - increments some sin parameter +// args[5] - fixed sin parameter +// args[6] - attacker or target void AnimParticleInVortex(struct Sprite *sprite) { if (IsDoubleBattle() diff --git a/src/battle_anim_utility_funcs.c b/src/battle_anim_utility_funcs.c index 47642b9fce..f43f13b748 100644 --- a/src/battle_anim_utility_funcs.c +++ b/src/battle_anim_utility_funcs.c @@ -722,6 +722,10 @@ void AnimTask_BlendNonAttackerPalettes(u8 taskId) StartBlendAnimSpriteColor(taskId, selectedPalettes); } +// gBattleAnimArgs[0] - initial x +// gBattleAnimArgs[1] - initial y +// gBattleAnimArgs[2] - negative? +// gBattleAnimArgs[3] - sentinel value to compare to void AnimTask_StartSlidingBg(u8 taskId) { u8 newTaskId; diff --git a/src/battle_anim_water.c b/src/battle_anim_water.c index 57053ef043..39be71c6b5 100644 --- a/src/battle_anim_water.c +++ b/src/battle_anim_water.c @@ -606,6 +606,10 @@ const struct SpriteTemplate gSparkBeamSpriteTemplate = .callback = AnimToTargetInSinWave, }; +// args[0] - initial sprite x +// args[1] - initial sprite y +// args[2] - attacker or target +// args[3] - affine anim number static void AnimAquaTail(struct Sprite *sprite) { StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]); @@ -618,6 +622,8 @@ static void AnimAquaTail(struct Sprite *sprite) StoreSpriteCallbackInData6(sprite, DestroyAnimSprite); } +// args[0] - initial x delta +// args[1] - initial y delta static void AnimKnockOffAquaTail(struct Sprite *sprite) { if (GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER) @@ -885,6 +891,7 @@ static void AnimToTargetInSinWave_Step(struct Sprite *sprite) } } +// args[0] - duration void AnimTask_StartSinAnimTimer(u8 taskId) { gTasks[taskId].data[0] = gBattleAnimArgs[0]; @@ -975,6 +982,10 @@ static void AnimWaterGunDroplet(struct Sprite *sprite) StoreSpriteCallbackInData6(sprite, DestroyAnimSprite); } +// args[0] - initial sprite x +// args[1] - initial sprite y +// args[2] - counter +// args[3] - attacker or target void AnimSmallBubblePair(struct Sprite *sprite) { if (gBattleAnimArgs[3] != ANIM_ATTACKER) From 3c8d5d1a57f38f984b8dfc93894f3bcf817b311b Mon Sep 17 00:00:00 2001 From: Bassoonian Date: Fri, 11 Apr 2025 16:38:08 +0200 Subject: [PATCH 15/19] Add hold effects for PLA Origin Trio items (#6578) --- src/data/items.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/data/items.h b/src/data/items.h index 2b560ad9d5..fc32e03042 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -13490,6 +13490,8 @@ const struct Item gItemsInfo[] = { .name = _("Adamant Crystal"), .price = 0, + .holdEffect = HOLD_EFFECT_ADAMANT_ORB, + .holdEffectParam = 20, .description = COMPOUND_STRING( "A large, glowing gem\n" "that lets Dialga\n" @@ -13506,6 +13508,8 @@ const struct Item gItemsInfo[] = { .name = _("Griseous Core"), .price = 0, + .holdEffect = HOLD_EFFECT_GRISEOUS_ORB, + .holdEffectParam = 20, .description = COMPOUND_STRING( "A large, glowing gem\n" "that lets Giratina\n" @@ -13522,6 +13526,8 @@ const struct Item gItemsInfo[] = { .name = _("Lustrous Globe"), .price = 0, + .holdEffect = HOLD_EFFECT_LUSTROUS_ORB, + .holdEffectParam = 20, .description = COMPOUND_STRING( "A large, glowing gem\n" "that lets Palkia\n" From 1ade4330283e861752d2d2684ffb1ead7b2cabc6 Mon Sep 17 00:00:00 2001 From: psf <77138753+pkmnsnfrn@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:59:43 -0700 Subject: [PATCH 16/19] Added call to ItemId_GetDescription (#6582) --- src/overworld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/overworld.c b/src/overworld.c index 52de83a153..7f38405bac 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -3348,7 +3348,7 @@ static u8 ReformatItemDescription(u16 item, u8 *dest) u8 count = 0; u8 numLines = 1; u8 maxChars = 32; - u8 *desc = (u8 *)gItemsInfo[item].description; + u8 *desc = (u8 *)ItemId_GetDescription(item); while (*desc != EOS) { From 3d8b912087e5e49db5999911dfd526bb511dd895 Mon Sep 17 00:00:00 2001 From: wiz1989 <80073265+wiz1989@users.noreply.github.com> Date: Sat, 12 Apr 2025 00:01:29 +0200 Subject: [PATCH 17/19] Ability imposter (#6552) --- src/battle_util.c | 23 ++++++++++++++--------- test/battle/ability/commander.c | 4 ++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index 8d5902d558..b012b177e3 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4763,16 +4763,21 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_IMPOSTER: - if (IsBattlerAlive(BATTLE_OPPOSITE(battler)) - && !(gBattleMons[BATTLE_OPPOSITE(battler)].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE)) - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) - && !(gBattleStruct->illusion[BATTLE_OPPOSITE(battler)].on) - && !(gStatuses3[BATTLE_OPPOSITE(battler)] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER)) { - gBattlerAttacker = battler; - gBattlerTarget = BATTLE_OPPOSITE(battler); - BattleScriptPushCursorAndCallback(BattleScript_ImposterActivates); - effect++; + u32 diagonalBattler = BATTLE_OPPOSITE(battler); + if (IsDoubleBattle()) + diagonalBattler = BATTLE_PARTNER(diagonalBattler); + if (IsBattlerAlive(diagonalBattler) + && !(gBattleMons[diagonalBattler].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE)) + && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + && !(gBattleStruct->illusion[diagonalBattler].on) + && !(gStatuses3[diagonalBattler] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER)) + { + gBattlerAttacker = battler; + gBattlerTarget = diagonalBattler; + BattleScriptPushCursorAndCallback(BattleScript_ImposterActivates); + effect++; + } } break; case ABILITY_MOLD_BREAKER: diff --git a/test/battle/ability/commander.c b/test/battle/ability/commander.c index 2220fb9ec2..d4b31f23b8 100644 --- a/test/battle/ability/commander.c +++ b/test/battle/ability/commander.c @@ -245,11 +245,11 @@ DOUBLE_BATTLE_TEST("Commander doesn't prevent Imposter from working on a Command OPPONENT(SPECIES_DITTO) { Ability(ABILITY_IMPOSTER); } } WHEN { TURN { } - TURN { SWITCH(opponentRight, 2); } + TURN { SWITCH(opponentLeft, 2); } } SCENE { ABILITY_POPUP(playerRight, ABILITY_COMMANDER); MESSAGE("Tatsugiri was swallowed by Dondozo and became Dondozo's commander!"); - ABILITY_POPUP(opponentRight, ABILITY_IMPOSTER); + ABILITY_POPUP(opponentLeft, ABILITY_IMPOSTER); MESSAGE("The opposing Ditto transformed into Tatsugiri using Imposter!"); } } From 1344d8e9ddf47f9061cc155328f6f6c29a0cb04d Mon Sep 17 00:00:00 2001 From: agsmgmaster64 <67435611+agsmgmaster64@users.noreply.github.com> Date: Fri, 11 Apr 2025 19:03:45 -0400 Subject: [PATCH 18/19] Type Effectiveness Indicators when selecting moves (#6559) --- charmap.txt | 1 + graphics/fonts/latin_narrow.png | Bin 4553 -> 4580 bytes graphics/fonts/latin_narrower.png | Bin 4617 -> 4258 bytes graphics/fonts/latin_normal.png | Bin 4661 -> 4686 bytes graphics/fonts/latin_short.png | Bin 4678 -> 4692 bytes graphics/fonts/latin_short_narrow.png | Bin 4993 -> 4621 bytes graphics/fonts/latin_short_narrower.png | Bin 4399 -> 4428 bytes graphics/fonts/latin_small.png | Bin 4587 -> 4621 bytes graphics/fonts/latin_small_narrow.png | Bin 4518 -> 4543 bytes graphics/fonts/latin_small_narrower.png | Bin 4349 -> 4371 bytes include/config/battle.h | 6 ++ src/battle_controller_player.c | 134 +++++++++++++++++++++++- src/battle_message.c | 8 +- src/fonts.c | 18 ++-- 14 files changed, 151 insertions(+), 16 deletions(-) diff --git a/charmap.txt b/charmap.txt index a35709d652..34fb683d0c 100644 --- a/charmap.txt +++ b/charmap.txt @@ -1064,6 +1064,7 @@ ROUND_RIGHT_PAREN = F9 14 CIRCLE_DOT = F9 15 TRIANGLE = F9 16 BIG_MULT_X = F9 17 +CIRCLE_HOLLOW = F9 18 EMOJI_UNDERSCORE = F9 D0 EMOJI_PIPE = F9 D1 diff --git a/graphics/fonts/latin_narrow.png b/graphics/fonts/latin_narrow.png index 434638ed17692ef98bf2c8cee733168c77144e99..bb9d0670d31b7c2e1fb82587ef85b958fcac4701 100644 GIT binary patch literal 4580 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 BK(7D* literal 4553 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 XTA6~m{)Yek)Bu+ZOmQXp_~`!t#W_z& diff --git a/graphics/fonts/latin_narrower.png b/graphics/fonts/latin_narrower.png index 19a6a98fb664f1084cb901ff4cb3fd550b9234dd..ab4ce4322ef2784ff24b5addda1a2edeab0a54c3 100644 GIT binary patch delta 1199 zcmeBFS)@2YdGcmP2_XiSk|4j}|3Hwd;a17OAmF(9EaN5a`iAX-MbX|M73fjoA&qg{N%&du_w~<+t|DUvr}Bz&=l^nu+{$9$T{tU9et*Q`#;ftC z_mV%aZJjqOd81|Uo zvvAClJT7>)_=Yc|Puw4YWs;9lqMyAvt!c7-S)af0Iz!eP*3T>qJ(H5zf7`vz(>!}8 z@lyX9#;}G3$IPzZ{}NUDMs@k0<3-PT7QNyV)8}YX;5amKz9d-@?Ae_R2SBROhj*cNFD0bJ>J(v(|g9o}ZRX z&z_YmyD;ZIul1eND^pvmSES}T{hhn_zQm_zhhK9o{9S)wnr3LPgn_)YYy*o$)AT*} z3ms|5ytQ?Jvr6Vn;D zG8pL|I()R4Ifr#y{k#h|UM2he_B=Le)t}y8){uE8!xkuBwDpOd@^`wShKy9hHis(? zHh-3U=@m)fcIYl-S&+r~&DN|V)&Iks>GnLOPZ#SN{MR=VDE)h@tl`VrZ@;+H28Nw&h^}0#8>zmvv4FO#ruj3Y7o= delta 1557 zcmb`G`9ISQ0LQnv=A6lW&XG__g(T*S$4y&J(lc^JThz!g=Qfk0hqaN)l`9Xgn&c+t zD2#GM3K3b8<54Oe=Eyw$gMN8FulG-%*ZZf>>-8zsysg8~CWCL`ZEev`wzi1Sn}i^I zNFWHLmzj`h>DUFR_V|oC+Zh-{Nr&~JAAT*>`s~g`-x4eFz`cJl_x2d>Eu*a2Osq;s z#7dqiWjNGg-YiC)6-ld0x?7r_z1dMVtTmRzC9zt0&2b{o^%J9&fW&ablK>z(S}zk;N9-3 z)MIupbaQpR8Jn5QfAtay#0|wQPKK0Y*1G-tYlhj*Ds`og;V8I+yIV!PCb#BwOnRM1 zRqedxmbmTdguvWoV+Tg3)_sKaEvkXDUYC8g$3wELxc(%a_yg8Ty6q+Q+}U@|6A)6q zG7jU5bhI|C-aT;nyq;7eAqtxa~WWQPr+VbO*p=B)WdD z;}`nCkPCqGiQ7620_0X`iWQDWZ32pW>!?ra&v_Pyi@**0H=vQ@e?eSst>cHM-Mf_8gM_o*D|{O8!0 z)C9*7IqguA>fZ|O_3Wl<2SDGL8o$LGi{k&d%K`)y>2Pr2o;`^sYYACV$`%CESYBH^ zI4C&n5Jiz%Tbx*bMH9UHtD5h%6}Ou%37^f(rL=XDfr|OB(Dc7f7C=X+)T!OqxWt zfxc;uQZKrY%j$@H&YprwS_|p= z8DQIECm}g#sUdRQ-Fw%soH?r+RAo~|bz}@?PU9COd$wU~dz_Jrs36FVs&tKtUSBoV zSq&NpVgh~o06HQg$kw{VRGePiG`?7LGoM%COFuQ1cFN0Lt|UiiGPzWL@FyXZUubf# zZ_ le@2|Ee))(mY27T#2k#7|##NrX5e3?hlik@rs%(6z{{fsc!Jq&D diff --git a/graphics/fonts/latin_normal.png b/graphics/fonts/latin_normal.png index d1de69d136c6fff2a296f42ee6e46c003f6c0493..b3fa87b0e08b678e002fd62104a3c5994ad83151 100644 GIT binary patch delta 1035 zcmV+m1oZp0B+ev|B#|)}5rQchF<|NsAOC`Nez01@r6N`ws!-8Jy`8hN+EMdnp!{^B)}X2*O10vdhcsMmv}ise;Zmv&;3xfMHv#|s zHLoZb4RgIX3vuHJS$R&jJunpoo(1^O*kS z81|5QAco*spdbxdNI*Y-KP*2N{#^cIQv|r%kEY&rKY-~)zDviqU`v<-0NobRnDVZ`n4cqHQK!>|mi$gw z;a(mZR=9>DZxhPz{QaQGo4?+F76`)!wsxte#en-5Q~(m-2wwBr-ULvgsL5f8+vH)F zamme%LWYCD5-lKqztxZ3;ZvtTVH52E?q46#JfE_o@CFgmyMCddEkO`Zy071rai3v7 zK9GP?b9@IQ1ikx%>^LBBKR+%!KYmO9$COu)%i@n!XY7`%h~_h&7DKnkJvk|7&{z*!`36_Xn+pN^I1innC5P}Ze6{R!6JM_ncIwlJcG%h|Xi##536P{Q<`{L1>*As}fX<49tPXU2Pj zY9>>}gmxf}#W(i%j;%Z9oN&+z{q>HV7I-$kAqYQ(f3AGB2=>AbbC&=B002ovPDHLk FV1krq{n7vc delta 1008 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 diff --git a/graphics/fonts/latin_short_narrow.png b/graphics/fonts/latin_short_narrow.png index 6bf1bae0cf26b424f8669cf50fab73e3c5a45c1d..b551f3215c7f38f00dc430a9d8e76392089f7a33 100644 GIT binary patch delta 4300 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 diff --git a/graphics/fonts/latin_short_narrower.png b/graphics/fonts/latin_short_narrower.png index 5c4f4c1d4d87a4dcbd5b58a6da7b03a920ad78bf..920a88aa01d0e6a144b615289b8ef6e9ae8609c5 100644 GIT binary patch delta 4187 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 delta 4151 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 B;sXEx diff --git a/graphics/fonts/latin_small.png b/graphics/fonts/latin_small.png index 41bb38cff8c3803e29a8ba0fda854f8182a94cbe..31c4444dc4694fad3f6f0ea7d1edaeb3e3f822fa 100644 GIT binary patch delta 3682 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 NbFxjk delta 3669 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 RytE~c){|^_0;~xM3 diff --git a/graphics/fonts/latin_small_narrow.png b/graphics/fonts/latin_small_narrow.png index ff07b857d7e91ea619ab5bfed1be35f517a3ce9f..4fbb13aad40a70f9dab4f364bf496ef04dd849a0 100644 GIT binary patch delta 1139 zcmZ3cykB{O%0xqPAqJL`Aiv=MK#;59R>{C17`M@D7I*#aCCpU}Y1g9skV2g5n$U<{r%adtWQ*?%VoGyWj+& z2b}+<{-pP@2Nq*<+P~M-?z(I#J^3B0Hp}c?!a0G^G5Hm%J`IKS>Ngo} zxb{m-=bC)_e>-pPgvtN+MJ;3bn|J=1e8QQ&oto8$-6!m-ODU}VW*qQp1w%;dwn?}C ztmWt0VR@8Y~Sb2P;B*Tr_epF1Cn#Z zjxpWfs?e@^E?jii;#x-D;boi;UY-q0%u;0gzV)nKj+1xhwx27H^3G~dogvP!=JLxQ z4R4K$<24Vjc3yn{GW!=cCf>N>f8O~=E?UoBxBvaCn#PWI=Wb7*3I=m;^7Y$qdBC^P zdH&w|g|8D98~1*3`_BH|=nTKQxebG}{-;=(`%UhLWEcuG5B)qHAZOH^@Feb$!>y{t z%^Rx@Z(O$2y7c*<-Jib&G$eNLI?Kqiy0G4Q7NTRI-M7-Mad&mj9o0OR{$38YcbQQQ zsT%nlkH7XXco)u5+Y*z1h&``xRrEu3lTT)i`#*kXuMgdK`-`q3kNlUdp1D~(JNld1 z8<->-uV>rFvuHGGl$>kMA9K5Snq!;|F>OTAT zWs%4|1;;&KcC$pYHCJ4E{OND-owy7A{48!eE%!AGGQIzE@TrBuhaXiw^YZ6w$43Ie z&1+ISmFrK=i>Oy=UCdCVd+6j*<7gd*A6##27jAxfyXc*|D0kZ@W=1w;_j$f8JP+!u zj%L43_@Bt<)y}j)UqDnq-Tq^ZSVIk?hT$~^nW(1ve%7QM*0^=4>dt5XUKEe`ca-T- zMEz^)13y(5{L0sVk*h90ym0m0GbSw4x8!k1HfaRJ8_m9Xj`Lytw*#N#{c0^M6b_`w zeXRW^v8VavMpn~?95J delta 1513 zcmdn5yi9q53KwH>kh>GZx^prwCn`!Y33_bwoyA>$`o`|&d4lt<{M#JYApR%)eEEr4 zF%17s%UMH!^Ir&t>KKll;p}wC$Yv7Rw?g#%oUh9<5;e!DPa>XBV zD_eR6(;dAFLQFjCQs33DX1vfI!RVp5LtJFSE*+5r`{h2Re=`5K_Px-7Iek^@TDCJ4 zuq|)h$gqv+9@qV!EivYOrn7Eu$YiRh+8jC~s^eg7?q>ek7lLNx)@2not0izgV`X?< zVr7@``^=s2Qy*Skc=7!UkV5=n;z+}#-i8@E}Ca-Zo+UKRM@ot$)eXT9{nWaXyD z>RDn5lBc8(RoE&Y2$EUOse66)hsNkRufl$C_U`e0kpJhe^EdbB4cU1zPKUK#NzU1S zFR8eGmrSddRmFR$W17Z0ug8nTl%$go) zUX0erxb#@6!T-<4r|fR`#N4hFSV@N;iSTSz Jmvv4FO#oI9=PLjJ diff --git a/graphics/fonts/latin_small_narrower.png b/graphics/fonts/latin_small_narrower.png index c20fa4ae4898071d6652f477576f14a9742faa88..69bca4645ac66404905d8275a827ffea46f6c93b 100644 GIT binary patch delta 1535 zcmeyXI9X|e%0xqPAqJL`Aiv=MK#;59R>{C1uxX>$XRdl9###Rf{hy%txvei z+sg1lk55@Ikuh(nE340^q^uUVhK2ikr!>sfzv|Myvcu(3M!;@-V~yDj4)9O4`7f1D3F^3+0@qd;%>9)`@! z%=cT%%dOH67cph&s4qB1fSNOHT3KOmxf3yJ>p|uLEf6;^RbN8LV5r@sm`}*~dMv)7 zrul@7uO|?egxpWad_u<8lNJ2arm=;2-EF%1>hqiX>4}UvpPsKy^$L*RW?s*pTz1Cy zCbwPFg|D`sUw^h>Uiyv8Av8mK<=ObGNKov*nTM7PVriAa_=*;&Mcni6s^6 z-F|bqZ-(w!GyAPO{De2KJZ5SLwUU*u-%y)&INa;|s|zpEe>FroEI5~)_vg~>>F_OioR*f5A3;HcSu?VnZy>#I=9ls#wfX*!I;80jATI6nbvP@^vp+JV6V(*?jnt4{7p@#L_ zybCv_Zdbjt7A^{%8h37#XUsw3M=D*7=HDtLO_BDh%%=vTVb0otj)&)l* zm!_=LaW+#Sh(*S=?XKAFMdZte2#cXq$#i+!82OmWAu zQ0Ef@E{(5d-8@sK$FZIL+W&%A*$viAI?n{{)A|ouN6ecY%zR>n!;8HY&q^I1=rnD= zDcm6QZN~b9$C^KmSl1ru6S(RYU~{yZ+tPPeJoAT6`~5Y?<4)W@)FI`U{_ZWF(ud}-kh>GZx^prwCn`!Y3C!Q<`Afn+Aqd52KucGG^7$ewq&bQB5e(%Ez z2i?-8UVeSY|8D7Qc|W}hhPJpTyLoE3uU}eo;v$cwnw1n-20e5W~TG&k3aeOZR00!Ampx{ zVExH+Tk=GaKBf~}3)IEW=j>y6puORH%eiYet`*;3Im39$dyWf|mY;HzQW(A$2ka@5 ze`9~v@nrzR7uG#YkDjQ{JI^#hpF#DQRD-kkhxZ#Dde$Czz4cAXik}OmKA1Ak2LQ^pUAxQ zSE|AP&(EjUZui98t`t~FhaZXXoWtN{{{KOh_tSso0t}BOFF!jXlHb*D70Mrcq$Ny& z_p!9ffsgkJW81DD_FMgWJ^u#p3Yq&m{uKQ@%{^gS+FSeUQPLY{?wmBA0SG)@{an^L HB{Ts5+D3eP diff --git a/include/config/battle.h b/include/config/battle.h index b61494ee44..59c90aacb0 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -323,6 +323,12 @@ #define SHOW_TYPES_SEEN 3 // Only show types if you've seen a species of the mon. #define B_SHOW_TYPES SHOW_TYPES_NEVER // When to show type indicators next to Pokémon health bars in battle, while choosing a move after selecting a target Pokémon. +#define SHOW_EFFECTIVENESS_NEVER 0 // Never show effectiveness when selecting moves. +#define SHOW_EFFECTIVENESS_ALWAYS 1 // Always show effectiveness when selecting moves. +#define SHOW_EFFECTIVENESS_CAUGHT 2 // Only show effectiveness if you've caught a species of the mon. +#define SHOW_EFFECTIVENESS_SEEN 3 // Only show effectiveness if you've seen a species of the mon. +#define B_SHOW_EFFECTIVENESS SHOW_EFFECTIVENESS_SEEN // If not SHOW_EFFECTIVENESS_NEVER, the PP string is replaced by a type effectiveness indicator based off the moves and the opposing side. + // Pokémon battle sprite settings #define B_ENEMY_MON_SHADOW_STYLE GEN_LATEST // In Gen4+, all enemy Pokemon will have a shadow drawn beneath them. diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 96f3e6b67d..dbbfeb40db 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -46,6 +46,7 @@ #include "menu.h" #include "pokemon_summary_screen.h" #include "type_icons.h" +#include "pokedex.h" static void PlayerBufferExecCompleted(u32 battler); static void PlayerHandleLoadMonSprite(u32 battler); @@ -99,6 +100,9 @@ static void Task_UpdateLvlInHealthbox(u8); static void PrintLinkStandbyMsg(void); static void ReloadMoveNames(u32 battler); +static u32 CheckTypeEffectiveness(u32 targetId, u32 battler); +static u32 CheckTargetTypeEffectiveness(u32 battler); +static void MoveSelectionDisplayMoveEffectiveness(u32 foeEffectiveness, u32 battler); static void (*const sPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = { @@ -502,6 +506,8 @@ void HandleInputChooseTarget(u32 battler) i++; break; } + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTypeEffectiveness(GetBattlerPosition(gMultiUsePlayerCursor), battler), battler); if (gAbsentBattlerFlags & (1u << gMultiUsePlayerCursor) || !CanTargetBattler(battler, gMultiUsePlayerCursor, move) @@ -551,6 +557,8 @@ void HandleInputChooseTarget(u32 battler) i++; break; } + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTypeEffectiveness(GetBattlerPosition(gMultiUsePlayerCursor), battler), battler); if (gAbsentBattlerFlags & (1u << gMultiUsePlayerCursor) || !CanTargetBattler(battler, gMultiUsePlayerCursor, move) @@ -749,6 +757,8 @@ void HandleInputChooseMove(u32 battler) gMultiUsePlayerCursor = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); else gMultiUsePlayerCursor = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTypeEffectiveness(GetBattlerPosition(gMultiUsePlayerCursor), battler), battler); gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_ShowAsMoveTarget; break; @@ -785,6 +795,8 @@ void HandleInputChooseMove(u32 battler) gMoveSelectionCursor[battler] ^= 1; PlaySE(SE_SELECT); MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler); MoveSelectionDisplayPpNumber(battler); MoveSelectionDisplayMoveType(battler); TryMoveSelectionDisplayMoveDescription(battler); @@ -800,6 +812,8 @@ void HandleInputChooseMove(u32 battler) gMoveSelectionCursor[battler] ^= 1; PlaySE(SE_SELECT); MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler); MoveSelectionDisplayPpNumber(battler); MoveSelectionDisplayMoveType(battler); TryMoveSelectionDisplayMoveDescription(battler); @@ -814,6 +828,8 @@ void HandleInputChooseMove(u32 battler) gMoveSelectionCursor[battler] ^= 2; PlaySE(SE_SELECT); MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler); MoveSelectionDisplayPpNumber(battler); MoveSelectionDisplayMoveType(battler); TryMoveSelectionDisplayMoveDescription(battler); @@ -829,6 +845,8 @@ void HandleInputChooseMove(u32 battler) gMoveSelectionCursor[battler] ^= 2; PlaySE(SE_SELECT); MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler); MoveSelectionDisplayPpNumber(battler); MoveSelectionDisplayMoveType(battler); TryMoveSelectionDisplayMoveDescription(battler); @@ -866,6 +884,8 @@ void HandleInputChooseMove(u32 battler) ClearStdWindowAndFrame(B_WIN_MOVE_DESCRIPTION, FALSE); CopyWindowToVram(B_WIN_MOVE_DESCRIPTION, COPYWIN_GFX); PlaySE(SE_SELECT); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler); MoveSelectionDisplayPpNumber(battler); MoveSelectionDisplayMoveType(battler); } @@ -900,6 +920,8 @@ static void ReloadMoveNames(u32 battler) MoveSelectionDestroyCursorAt(battler); MoveSelectionDisplayMoveNames(battler); MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler); MoveSelectionDisplayPpNumber(battler); MoveSelectionDisplayMoveType(battler); } @@ -1052,7 +1074,10 @@ void HandleMoveSwitching(u32 battler) gBattlerControllerFuncs[battler] = HandleInputChooseMove; gMoveSelectionCursor[battler] = gMultiUsePlayerCursor; MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0); - MoveSelectionDisplayPpString(battler); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler); + else + MoveSelectionDisplayPpString(battler); MoveSelectionDisplayPpNumber(battler); MoveSelectionDisplayMoveType(battler); AssignUsableZMoves(battler, moveInfo->moves); @@ -1063,7 +1088,10 @@ void HandleMoveSwitching(u32 battler) MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor); MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0); gBattlerControllerFuncs[battler] = HandleInputChooseMove; - MoveSelectionDisplayPpString(battler); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler); + else + MoveSelectionDisplayPpString(battler); MoveSelectionDisplayPpNumber(battler); MoveSelectionDisplayMoveType(battler); } @@ -2152,7 +2180,10 @@ void InitMoveSelectionsVarsAndStrings(u32 battler) MoveSelectionDisplayMoveNames(battler); gMultiUsePlayerCursor = 0xFF; MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0); - MoveSelectionDisplayPpString(battler); + if (B_SHOW_EFFECTIVENESS) + MoveSelectionDisplayMoveEffectiveness(CheckTargetTypeEffectiveness(battler), battler); + else + MoveSelectionDisplayPpString(battler); MoveSelectionDisplayPpNumber(battler); MoveSelectionDisplayMoveType(battler); } @@ -2386,3 +2417,100 @@ static void PlayerHandleBattleDebug(u32 battler) SetMainCallback2(CB2_BattleDebugMenu); gBattlerControllerFuncs[battler] = Controller_WaitForDebug; } + +// Order based numerically, with EFFECTIVENESS_CANNOT_VIEW at 0 to always prioritize any other effectiveness during comparison +enum +{ + EFFECTIVENESS_CANNOT_VIEW, + EFFECTIVENESS_NO_EFFECT, + EFFECTIVENESS_NOT_VERY_EFFECTIVE, + EFFECTIVENESS_NORMAL, + EFFECTIVENESS_SUPER_EFFECTIVE, +}; + +static bool32 ShouldShowTypeEffectiveness(u32 targetId) +{ + if (B_SHOW_EFFECTIVENESS == SHOW_EFFECTIVENESS_CAUGHT) + return GetSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[targetId].species), FLAG_GET_CAUGHT); + + if (B_SHOW_EFFECTIVENESS == SHOW_EFFECTIVENESS_SEEN) + return GetSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[targetId].species), FLAG_GET_SEEN); + + return TRUE; +} + +static u32 CheckTypeEffectiveness(u32 targetId, u32 battler) +{ + struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); + struct Pokemon *mon = &gPlayerParty[gBattlerPartyIndexes[battler]]; + u32 move = moveInfo->moves[gMoveSelectionCursor[battler]]; + u32 moveType = CheckDynamicMoveType(mon, move, battler); + uq4_12_t modifier = CalcTypeEffectivenessMultiplier(move, moveType, battler, targetId, GetBattlerAbility(targetId), FALSE); + + if (!ShouldShowTypeEffectiveness(targetId)) + return EFFECTIVENESS_CANNOT_VIEW; + + if (modifier == UQ_4_12(0.0)) + return EFFECTIVENESS_NO_EFFECT; // No effect + else if (modifier <= UQ_4_12(0.5)) + return EFFECTIVENESS_NOT_VERY_EFFECTIVE; // Not very effective + else if (modifier >= UQ_4_12(2.0)) + return EFFECTIVENESS_SUPER_EFFECTIVE; // Super effective + return EFFECTIVENESS_NORMAL; // Normal effectiveness +} + +static u32 CheckTargetTypeEffectiveness(u32 battler) +{ + u32 battlerFoe = BATTLE_OPPOSITE(GetBattlerPosition(battler)); + u32 foeEffectiveness = CheckTypeEffectiveness(battlerFoe, battler); + + if (IsDoubleBattle()) + { + u32 partnerFoe = BATTLE_PARTNER(battlerFoe); + u32 partnerFoeEffectiveness = CheckTypeEffectiveness(partnerFoe, battler); + if (!IsBattlerAlive(battlerFoe)) + return partnerFoeEffectiveness; + if (IsBattlerAlive(battlerFoe) && IsBattlerAlive(partnerFoe) + && partnerFoeEffectiveness > foeEffectiveness) + return partnerFoeEffectiveness; + } + return foeEffectiveness; // fallthrough for any other circumstance +} + +static void MoveSelectionDisplayMoveEffectiveness(u32 foeEffectiveness, u32 battler) +{ + static const u8 noIcon[] = _(""); + static const u8 effectiveIcon[] = _("{CIRCLE_HOLLOW}"); + static const u8 superEffectiveIcon[] = _("{CIRCLE_DOT}"); + static const u8 notVeryEffectiveIcon[] = _("{TRIANGLE}"); + static const u8 immuneIcon[] = _("{BIG_MULT_X}"); + struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); + u8 *txtPtr; + + txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfacePP); + + if (!IsBattleMoveStatus(moveInfo->moves[gMoveSelectionCursor[battler]])) + { + switch (foeEffectiveness) + { + case EFFECTIVENESS_SUPER_EFFECTIVE: + StringCopy(txtPtr, superEffectiveIcon); + break; + case EFFECTIVENESS_NOT_VERY_EFFECTIVE: + StringCopy(txtPtr, notVeryEffectiveIcon); + break; + case EFFECTIVENESS_NO_EFFECT: + StringCopy(txtPtr, immuneIcon); + break; + case EFFECTIVENESS_NORMAL: + StringCopy(txtPtr, effectiveIcon); + break; + default: + case EFFECTIVENESS_CANNOT_VIEW: + StringCopy(txtPtr, noIcon); + break; + } + } + + BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_PP); +} diff --git a/src/battle_message.c b/src/battle_message.c index cf25e7c221..2887e1512e 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -1635,9 +1635,9 @@ static const struct BattleWindowText sTextOnWindowsInfo_Normal[] = .x = 0, .y = 1, .speed = 0, - .fgColor = 12, + .fgColor = B_SHOW_EFFECTIVENESS != SHOW_EFFECTIVENESS_NEVER ? 13 : 12, .bgColor = 14, - .shadowColor = 11, + .shadowColor = B_SHOW_EFFECTIVENESS != SHOW_EFFECTIVENESS_NEVER ? 15 : 11, }, [B_WIN_DUMMY] = { .fillValue = PIXEL_FILL(0xE), @@ -1887,9 +1887,9 @@ static const struct BattleWindowText sTextOnWindowsInfo_Arena[] = .x = 0, .y = 1, .speed = 0, - .fgColor = 12, + .fgColor = B_SHOW_EFFECTIVENESS != SHOW_EFFECTIVENESS_NEVER ? 13 : 12, .bgColor = 14, - .shadowColor = 11, + .shadowColor = B_SHOW_EFFECTIVENESS != SHOW_EFFECTIVENESS_NEVER ? 15 : 11, }, [B_WIN_DUMMY] = { .fillValue = PIXEL_FILL(0xE), diff --git a/src/fonts.c b/src/fonts.c index 853f6fbde2..46f3a335c4 100644 --- a/src/fonts.c +++ b/src/fonts.c @@ -19,7 +19,7 @@ ALIGNED(4) const u8 gFontSmallNarrowLatinGlyphWidths[] = { 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 3, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 8, 3, 3, 3, 3, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -55,7 +55,7 @@ ALIGNED(4) const u8 gFontSmallLatinGlyphWidths[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 8, 7, 5, 5, 5, 5, 5, 5, 9, 3, 3, 3, 8, 3, 3, 3, 3, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -91,7 +91,7 @@ ALIGNED(4) const u8 gFontNarrowLatinGlyphWidths[] = { 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 8, 3, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 8, 3, 3, 3, 3, 10, 10, 10, 10, 8, 8, 10, 8, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -127,7 +127,7 @@ ALIGNED(4) const u8 gFontShortLatinGlyphWidths[] = { 5, 6, 5, 6, 6, 6, 5, 5, 5, 6, 6, 6, 6, 6, 6, 8, 5, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 8, 3, 3, 3, 3, 12, 12, 12, 12, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -163,7 +163,7 @@ ALIGNED(4) const u8 gFontNormalLatinGlyphWidths[] = { 4, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 8, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 8, 3, 3, 3, 3, 10, 10, 10, 10, 8, 10, 10, 8, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -199,7 +199,7 @@ ALIGNED(4) const u8 gFontNarrowerLatinGlyphWidths[] = { 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 2, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 8, 3, 3, 3, 3, 10, 10, 10, 10, 8, 8, 10, 8, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -235,7 +235,7 @@ ALIGNED(4) const u8 gFontSmallNarrowerLatinGlyphWidths[] = { 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 2, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 8, 3, 3, 3, 3, 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -271,7 +271,7 @@ ALIGNED(4) const u8 gFontShortNarrowLatinGlyphWidths[] = { 4, 6, 5, 5, 5, 5, 5, 5, 4, 5, 5, 6, 4, 5, 5, 8, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 8, 3, 3, 3, 3, 12, 12, 12, 12, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -307,7 +307,7 @@ ALIGNED(4) const u8 gFontShortNarrowerLatinGlyphWidths[] = { 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 5, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10, 10, 10, 10, 8, 8, 10, 8, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, From e146940f250fc5dda02076e5cb8d09b62fd0156b Mon Sep 17 00:00:00 2001 From: psf <77138753+pkmnsnfrn@users.noreply.github.com> Date: Sat, 12 Apr 2025 01:23:48 -0700 Subject: [PATCH 19/19] Add B_LEVEL_UP_NOTIFICATION to improve player QoL when performing multiple level ups (#4901) Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- include/battle.h | 1 + include/config/battle.h | 1 + include/pokemon.h | 1 + src/battle_controller_player.c | 21 ++++++++++++++------- src/battle_script_commands.c | 33 +++++++++++++++++++++++++++++---- src/pokemon.c | 8 ++++++-- 6 files changed, 52 insertions(+), 13 deletions(-) diff --git a/include/battle.h b/include/battle.h index dbeb791867..9a627b16b0 100644 --- a/include/battle.h +++ b/include/battle.h @@ -396,6 +396,7 @@ struct BattleCallbacksStack struct StatsArray { u16 stats[NUM_STATS]; + u16 level; }; struct BattleResources diff --git a/include/config/battle.h b/include/config/battle.h index 59c90aacb0..a252edba92 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -16,6 +16,7 @@ #define B_SPLIT_EXP GEN_LATEST // In Gen6+, all participating mon get full experience. #define B_SCALED_EXP GEN_LATEST // In Gen5 and Gen7+, experience is weighted by level difference. #define B_UNEVOLVED_EXP_MULTIPLIER GEN_LATEST // In Gen6+, if the Pokémon is at or past the level where it would be able to evolve, but it has not, it gets a ~1.2 multiplier to EXP gain. Only applies to Pokémon with EVO_LEVEL method. +#define B_LEVEL_UP_NOTIFICATION GEN_LATEST // In Gen9+, if the Pokémon gets enough experience to level up multiple times, the message is only displayed once. // Stat settings #define B_BADGE_BOOST GEN_LATEST // In Gen4+, Gym Badges no longer boost a Pokémon's stats. diff --git a/include/pokemon.h b/include/pokemon.h index 0c3deb2f72..7e048ef015 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -658,6 +658,7 @@ void SetMonMoveSlot(struct Pokemon *mon, u16 move, u8 slot); void SetBattleMonMoveSlot(struct BattlePokemon *mon, u16 move, u8 slot); void GiveMonInitialMoveset(struct Pokemon *mon); void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon); +u16 MonTryLearningNewMoveAtLevel(struct Pokemon *mon, bool32 firstMove, u32 level); u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove); void DeleteFirstMoveAndGiveMoveToMon(struct Pokemon *mon, u16 move); void DeleteFirstMoveAndGiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move); diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index dbbfeb40db..cd69f2ab1a 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -1453,11 +1453,13 @@ static void Task_GiveExpToMon(u8 taskId) u8 level = GetMonData(mon, MON_DATA_LEVEL); u32 currExp = GetMonData(mon, MON_DATA_EXP); u32 nextLvlExp = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1]; + u32 expAfterGain = currExp + gainedExp; u32 oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP); - if (currExp + gainedExp >= nextLvlExp) + if (expAfterGain >= nextLvlExp) { - SetMonData(mon, MON_DATA_EXP, &nextLvlExp); + SetMonData(mon, MON_DATA_EXP, (B_LEVEL_UP_NOTIFICATION >= GEN_9) ? &expAfterGain : &nextLvlExp); + CalculateMonStats(mon); // Reapply Dynamax HP multiplier after stats are recalculated. @@ -1465,7 +1467,7 @@ static void Task_GiveExpToMon(u8 taskId) DynamaxModifyHPLevelUp(mon, battler, oldMaxHP); gainedExp -= nextLvlExp - currExp; - BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, (B_LEVEL_UP_NOTIFICATION >= GEN_9) ? 0 : gainedExp); if (IsDoubleBattle() == TRUE && (monId == gBattlerPartyIndexes[battler] || monId == gBattlerPartyIndexes[BATTLE_PARTNER(battler)])) @@ -1509,7 +1511,7 @@ static void Task_PrepareToGiveExpWithExpBar(u8 taskId) static void Task_GiveExpWithExpBar(u8 taskId) { - u8 level; + u32 level, expAfterGain; u16 species; u32 oldMaxHP; s32 currExp, expOnNextLvl, newExpPoints; @@ -1536,9 +1538,14 @@ static void Task_GiveExpWithExpBar(u8 taskId) oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP); expOnNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1]; - if (currExp + gainedExp >= expOnNextLvl) + expAfterGain = currExp + gainedExp; + if (expAfterGain >= expOnNextLvl) { - SetMonData(mon, MON_DATA_EXP, &expOnNextLvl); + if (B_LEVEL_UP_NOTIFICATION >= GEN_9) + SetMonData(mon, MON_DATA_EXP, &expAfterGain); + else + SetMonData(mon, MON_DATA_EXP, &expOnNextLvl); + CalculateMonStats(mon); // Reapply Dynamax HP multiplier after stats are recalculated. @@ -1546,7 +1553,7 @@ static void Task_GiveExpWithExpBar(u8 taskId) DynamaxModifyHPLevelUp(mon, battler, oldMaxHP); gainedExp -= expOnNextLvl - currExp; - BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, (B_LEVEL_UP_NOTIFICATION >= GEN_9) ? 0 : gainedExp); gTasks[taskId].func = Task_LaunchLvlUpAnim; } else diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index dca87252e0..671203448b 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -5100,6 +5100,7 @@ static void Cmd_getexp(void) u32 holdEffect; s32 i; // also used as stringId u8 *expMonId = &gBattleStruct->expGetterMonId; + u32 currLvl; gBattlerFainted = GetBattlerForBattleScript(cmd->battler); @@ -5314,7 +5315,8 @@ static void Cmd_getexp(void) if (gBattleControllerExecFlags == 0) { gBattleResources->bufferB[gBattleStruct->expGetterBattlerId][0] = 0; - if (GetMonData(&gPlayerParty[*expMonId], MON_DATA_HP) && GetMonData(&gPlayerParty[*expMonId], MON_DATA_LEVEL) != MAX_LEVEL) + currLvl = GetMonData(&gPlayerParty[*expMonId], MON_DATA_LEVEL); + if (GetMonData(&gPlayerParty[*expMonId], MON_DATA_HP) && currLvl != MAX_LEVEL) { gBattleResources->beforeLvlUp->stats[STAT_HP] = GetMonData(&gPlayerParty[*expMonId], MON_DATA_MAX_HP); gBattleResources->beforeLvlUp->stats[STAT_ATK] = GetMonData(&gPlayerParty[*expMonId], MON_DATA_ATK); @@ -5322,6 +5324,7 @@ static void Cmd_getexp(void) gBattleResources->beforeLvlUp->stats[STAT_SPEED] = GetMonData(&gPlayerParty[*expMonId], MON_DATA_SPEED); gBattleResources->beforeLvlUp->stats[STAT_SPATK] = GetMonData(&gPlayerParty[*expMonId], MON_DATA_SPATK); gBattleResources->beforeLvlUp->stats[STAT_SPDEF] = GetMonData(&gPlayerParty[*expMonId], MON_DATA_SPDEF); + gBattleResources->beforeLvlUp->level = currLvl; BtlController_EmitExpUpdate(gBattleStruct->expGetterBattlerId, BUFFER_A, *expMonId, gBattleStruct->battlerExpReward); MarkBattlerForControllerExec(gBattleStruct->expGetterBattlerId); @@ -8643,10 +8646,32 @@ static void Cmd_handlelearnnewmove(void) { CMD_ARGS(const u8 *learnedMovePtr, const u8 *nothingToLearnPtr, bool8 isFirstMove); + u16 learnMove = MOVE_NONE; u32 monId = gBattleStruct->expGetterMonId; - u16 learnMove = MonTryLearningNewMove(&gPlayerParty[monId], cmd->isFirstMove); - while (learnMove == MON_ALREADY_KNOWS_MOVE) - learnMove = MonTryLearningNewMove(&gPlayerParty[monId], FALSE); + + if (B_LEVEL_UP_NOTIFICATION >= GEN_9) + { + u32 currLvl = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL); + + while (gBattleResources->beforeLvlUp->level <= currLvl) + { + learnMove = MonTryLearningNewMoveAtLevel(&gPlayerParty[monId], cmd->isFirstMove, gBattleResources->beforeLvlUp->level); + + while (learnMove == MON_ALREADY_KNOWS_MOVE) + learnMove = MonTryLearningNewMoveAtLevel(&gPlayerParty[monId], FALSE, gBattleResources->beforeLvlUp->level); + + if (learnMove != MOVE_NONE) + break; + + gBattleResources->beforeLvlUp->level++; + } + } + else + { + learnMove = MonTryLearningNewMove(&gPlayerParty[monId], cmd->isFirstMove); + while (learnMove == MON_ALREADY_KNOWS_MOVE) + learnMove = MonTryLearningNewMove(&gPlayerParty[monId], FALSE); + } if (learnMove == MOVE_NONE || RECORDED_WILD_BATTLE) { diff --git a/src/pokemon.c b/src/pokemon.c index 0289ca180e..29407b8961 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -1982,11 +1982,10 @@ void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon) //Credit: AsparagusEdua } } -u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove) +u16 MonTryLearningNewMoveAtLevel(struct Pokemon *mon, bool32 firstMove, u32 level) { u32 retVal = MOVE_NONE; u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); - u8 level = GetMonData(mon, MON_DATA_LEVEL, NULL); const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species); // since you can learn more than one move per level @@ -2034,6 +2033,11 @@ u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove) return retVal; } +u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove) +{ + return MonTryLearningNewMoveAtLevel(mon, firstMove, GetMonData(mon, MON_DATA_LEVEL, NULL)); +} + void DeleteFirstMoveAndGiveMoveToMon(struct Pokemon *mon, u16 move) { s32 i;