diff --git a/gflib/sprite.c b/gflib/sprite.c index 7823888cb529..9ba1662c9ddd 100644 --- a/gflib/sprite.c +++ b/gflib/sprite.c @@ -52,7 +52,6 @@ static void SortSprites(u32 *spritePriorities, s32 n); static u32 CreateSpriteAt(u32 index, const struct SpriteTemplate *template, s16 x, s16 y, u32 subpriority); static void ResetOamMatrices(void); static void ResetSprite(struct Sprite *sprite); -static void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images); static void ResetAllSprites(void); static void BeginAnim(struct Sprite *sprite); static void ContinueAnim(struct Sprite *sprite); @@ -75,7 +74,6 @@ static void AffineAnimCmd_end(u8 matrixNum, struct Sprite *sprite); static void AffineAnimCmd_frame(u8 matrixNum, struct Sprite *sprite); static void CopyOamMatrix(u8 destMatrixIndex, struct OamMatrix *srcMatrix); static u8 GetSpriteMatrixNum(struct Sprite *sprite); -static void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); static void AffineAnimStateRestartAnim(u8 matrixNum); static void AffineAnimStateStartAnim(u8 matrixNum, u8 animNum); static void AffineAnimStateReset(u8 matrixNum); diff --git a/gflib/sprite.h b/gflib/sprite.h index 6a3084add254..937ed42ced5f 100644 --- a/gflib/sprite.h +++ b/gflib/sprite.h @@ -331,5 +331,7 @@ u8 SpriteTileAllocBitmapOp(u16 bit, u8 op); void ClearSpriteCopyRequests(void); void ResetAffineAnimData(void); u32 GetSpanPerImage(u32 shape, u32 size); +void RequestSpriteFrameImageCopy(u16 index, u16 tileNum, const struct SpriteFrameImage *images); +void SetSpriteOamFlipBits(struct Sprite *sprite, u8 hFlip, u8 vFlip); #endif //GUARD_SPRITE_H diff --git a/graphics/types/battle_icons1.pal b/graphics/types/battle_icons1.pal new file mode 100644 index 000000000000..972dfd02af2c --- /dev/null +++ b/graphics/types/battle_icons1.pal @@ -0,0 +1,15 @@ +JASC-PAL +0100 +12 +120 152 128 +49 49 49 +255 255 255 +164 82 57 +172 189 32 +184 160 90 +213 180 90 +98 98 180 +180 90 164 +172 164 148 +172 172 197 +152 172 246 diff --git a/graphics/types/battle_icons1.png b/graphics/types/battle_icons1.png new file mode 100644 index 000000000000..c47b07f1171a Binary files /dev/null and b/graphics/types/battle_icons1.png differ diff --git a/graphics/types/battle_icons2.pal b/graphics/types/battle_icons2.pal new file mode 100644 index 000000000000..bddf49ad9547 --- /dev/null +++ b/graphics/types/battle_icons2.pal @@ -0,0 +1,15 @@ +JASC-PAL +0100 +12 +120 152 128 +49 49 49 +255 255 255 +240 82 48 +120 200 80 +248 197 49 +80 120 136 +123 98 230 +248 115 164 +57 156 255 +90 205 230 +246 180 246 diff --git a/graphics/types/battle_icons2.png b/graphics/types/battle_icons2.png new file mode 100644 index 000000000000..44aa4f89547f Binary files /dev/null and b/graphics/types/battle_icons2.png differ diff --git a/include/battle.h b/include/battle.h index 3d2b05349fad..dd2ca35f61da 100644 --- a/include/battle.h +++ b/include/battle.h @@ -1131,6 +1131,13 @@ static inline u32 GetBattlerSide(u32 battler) return GetBattlerPosition(battler) & BIT_SIDE; } +static inline struct Pokemon* GetBattlerData(u32 battlerId) +{ + u32 index = gBattlerPartyIndexes[battlerId]; + + return (GetBattlerSide(battlerId) == B_SIDE_OPPONENT) ? &gEnemyParty[index] : &gPlayerParty[index]; +} + static inline struct Pokemon *GetSideParty(u32 side) { return (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; @@ -1141,4 +1148,9 @@ static inline struct Pokemon *GetBattlerParty(u32 battler) return GetSideParty(GetBattlerSide(battler)); } +static inline bool32 IsDoubleBattle(void) +{ + return gBattleTypeFlags & BATTLE_TYPE_DOUBLE; +} + #endif // GUARD_BATTLE_H diff --git a/include/battle_anim.h b/include/battle_anim.h index ce9749685ef6..b3460fd6bc7e 100644 --- a/include/battle_anim.h +++ b/include/battle_anim.h @@ -194,7 +194,6 @@ u8 GetBattlerSpriteCoord(u8 battlerId, u8 attributeId); bool8 IsBattlerSpritePresent(u8 battlerId); void ClearBattleAnimBg(u32 bgId); u8 GetAnimBattlerSpriteId(u8 wantedBattler); -bool8 IsDoubleBattle(void); u8 GetBattleBgPaletteNum(void); u8 GetBattlerSpriteBGPriorityRank(u8 battlerId); void StoreSpriteCallbackInData6(struct Sprite *sprite, void (*spriteCallback)(struct Sprite *)); diff --git a/include/battle_controllers.h b/include/battle_controllers.h index 71a769144882..50860a7285d4 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -310,6 +310,11 @@ void ActionSelectionDestroyCursorAt(u8 cursorPos); void InitMoveSelectionsVarsAndStrings(u32 battler); void MoveSelectionCreateCursorAt(u8 cursorPos, u8 arg1); void MoveSelectionDestroyCursorAt(u8 cursorPosition); +void PlayerHandleChooseMove(u32 battler); +void HandleInputChooseMove(u32 battler); +void HandleInputChooseTarget(u32 battler); +void HandleMoveSwitching(u32 battler); +void HandleChooseMoveAfterDma3(u32 battler); // recorded player controller void SetControllerToRecordedPlayer(u32 battler); diff --git a/include/config/battle.h b/include/config/battle.h index d867a223d95f..72fda7f76cab 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -273,4 +273,9 @@ #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. + #endif // GUARD_CONFIG_BATTLE_H diff --git a/include/constants/battle.h b/include/constants/battle.h index 1f11adbd5f4e..39d52d3a45ac 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -89,7 +89,6 @@ #define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gTrainerBattleOpponent_B == 0xFFFF)) #define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER | BATTLE_TYPE_INGAME_PARTNER) - // Battle Outcome defines #define B_OUTCOME_WON 1 #define B_OUTCOME_LOST 2 diff --git a/include/data.h b/include/data.h index 69c1a19a3c49..88111eb5c020 100644 --- a/include/data.h +++ b/include/data.h @@ -110,7 +110,9 @@ struct TypeInfo u16 maxMove; u16 teraTypeRGBValue; // Most values pulled from the Tera type icon palette. u16 damageCategory:2; // Used for B_PHYSICAL_SPECIAL_SPLIT <= GEN_3 - u16 padding:14; + u16 useSecondTypeIconPalette:1; + u16 isSpecialCaseType:1; + u16 padding:12; const u32 *const paletteTMHM; //u16 enhanceItem; //u16 berry; diff --git a/include/graphics.h b/include/graphics.h index 01de060b790d..9e6f53b3e496 100644 --- a/include/graphics.h +++ b/include/graphics.h @@ -3363,4 +3363,9 @@ extern const u8 gMailTilemap_Retro[]; extern const u8 gMonMarkingsMenu_Gfx[]; extern const u16 gMonMarkingsMenu_Pal[]; +extern const u32 gBattleIcons_Gfx1[]; +extern const u32 gBattleIcons_Gfx2[]; +extern const u32 gBattleIcons_Pal1[]; +extern const u32 gBattleIcons_Pal2[]; + #endif //GUARD_GRAPHICS_H diff --git a/include/type_icons.h b/include/type_icons.h new file mode 100644 index 000000000000..1d6a312f072e --- /dev/null +++ b/include/type_icons.h @@ -0,0 +1,18 @@ +#ifndef GUARD_TYPE_ICONS_H +#define GUARD_TYPE_ICONS_H + +void LoadTypeIcons(u32); + +#define TYPE_ICON_TAG 0x2720 +#define TYPE_ICON_TAG_2 0x2721 +#define NUM_FRAMES_HIDE_TYPE_ICON 10 + +#define tMonPosition data[0] +#define tBattlerId data[1] +#define tHideIconTimer data[2] +#define tVerticalPosition data[3] + +#define TYPE_ICON_1_FRAME(monType) ((monType - 1) * 2) +#define TYPE_ICON_2_FRAME(monType) ((monType - 11) * 2) + +#endif // GUARD_TYPE_ICONS_H diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 68c7bc770fd7..c81421076643 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -174,7 +174,7 @@ static u32 GetAiFlags(u16 trainerId) flags = GetTrainerAIFlagsFromId(trainerId); } - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { flags |= AI_FLAG_DOUBLE_BATTLE; } @@ -224,7 +224,7 @@ void BattleAI_SetupFlags(void) { AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)); } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsAiVsAiBattle()) + else if (IsDoubleBattle() && IsAiVsAiBattle()) { AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT]; } @@ -275,7 +275,7 @@ u32 BattleAI_ChooseMoveOrAction(void) { u32 ret; - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!IsDoubleBattle()) ret = ChooseMoveOrAction_Singles(sBattler_AI); else ret = ChooseMoveOrAction_Doubles(sBattler_AI); @@ -323,7 +323,7 @@ void Ai_InitPartyStruct(void) // Save first 2 or 4(in doubles) mons CopyBattlerDataToAIParty(B_POSITION_PLAYER_LEFT, B_SIDE_PLAYER); - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) CopyBattlerDataToAIParty(B_POSITION_PLAYER_RIGHT, B_SIDE_PLAYER); // If player's partner is AI, save opponent mons @@ -2050,7 +2050,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } /*if (AI_THINKING_STRUCT->aiFlags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI - && IS_DOUBLE_BATTLE) //Make the regular AI know how to use Protect minimally in Doubles + && IsDoubleBattle()) //Make the regular AI know how to use Protect minimally in Doubles { u8 shouldProtect = ShouldProtect(battlerAtk, battlerDef, move); if (shouldProtect == USE_PROTECT || shouldProtect == PROTECT_FROM_FOES) diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index ef35a95f59cc..966082f32f5d 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -82,7 +82,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult) return FALSE; // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) return FALSE; opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); @@ -242,7 +242,7 @@ static bool32 ShouldSwitchIfWonderGuard(u32 battler, bool32 emitResult) struct Pokemon *party = NULL; u16 move; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) return FALSE; opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); @@ -318,7 +318,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler, bool32 emitResult) if (IS_MOVE_STATUS(gLastLandedMoves[battler])) return FALSE; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { battlerIn1 = battler; if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))]) @@ -707,7 +707,7 @@ static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng) } } } - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!IsDoubleBattle()) return FALSE; opposingBattler = GetBattlerAtPosition(BATTLE_PARTNER(opposingPosition)); @@ -765,7 +765,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 modu if (IS_MOVE_STATUS(gLastLandedMoves[battler])) return FALSE; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { battlerIn1 = battler; if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))]) @@ -846,7 +846,7 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler) // Battler will faint to hazards, check to see if another mon can clear them if (hazardDamage > battlerHp) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { battlerIn1 = battler; if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))]) @@ -1023,7 +1023,7 @@ bool32 ShouldSwitch(u32 battler, bool32 emitResult) availableToSwitch = 0; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { battlerIn1 = battler; if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))]) @@ -1140,7 +1140,7 @@ void AI_TrySwitchOrUseItem(u32 battler) s32 monToSwitchId = AI_DATA->mostSuitableMonId[battler]; if (monToSwitchId == PARTY_SIZE) { - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!IsDoubleBattle()) { battlerIn1 = GetBattlerAtPosition(battlerPosition); battlerIn2 = battlerIn1; @@ -2040,7 +2040,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd) if (gBattleTypeFlags & BATTLE_TYPE_ARENA) return gBattlerPartyIndexes[battler] + 1; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { battlerIn1 = battler; if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battler)))]) @@ -2074,7 +2074,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd) // Split ideal mon decision between after previous mon KO'd (prioritize offensive options) and after switching active mon out (prioritize defensive options), and expand the scope of both. // Only use better mon selection if AI_FLAG_SMART_MON_CHOICES is set for the trainer. - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_MON_CHOICES && !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic + if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic { bestMonId = GetBestMonIntegrated(party, firstId, lastId, battler, opposingBattler, battlerIn1, battlerIn2, switchAfterMonKOd); return bestMonId; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 2af88bea8c1d..26950882f1e3 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -3026,7 +3026,7 @@ bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof) else party = gEnemyParty; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { battlerOnField1 = gBattlerPartyIndexes[battlerId]; battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))]; @@ -3417,7 +3417,7 @@ s32 CountUsablePartyMons(u32 battlerId) else party = gEnemyParty; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { battlerOnField1 = gBattlerPartyIndexes[battlerId]; battlerOnField2 = gBattlerPartyIndexes[GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(battlerId)))]; @@ -3828,7 +3828,7 @@ bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move) bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove) { // simple logic. just upgrades chosen move to z move if possible, unless regular move would kill opponent - if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && battlerDef == BATTLE_PARTNER(battlerAtk)) + if ((IsDoubleBattle()) && battlerDef == BATTLE_PARTNER(battlerAtk)) return FALSE; // don't use z move on partner if (HasTrainerUsedGimmick(battlerAtk, GIMMICK_Z_MOVE)) return FALSE; // can't use z move twice diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index b917cdc9a57a..a85203313354 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -3317,7 +3317,7 @@ static void AnimSolarBeamSmallOrb(struct Sprite *sprite) { InitSpritePosToAnimAttacker(sprite, TRUE); - if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gAnimMoveIndex == MOVE_CORE_ENFORCER) + if (IsDoubleBattle() && gAnimMoveIndex == MOVE_CORE_ENFORCER) { CoreEnforcerLoadBeamTarget(sprite); } @@ -6567,11 +6567,11 @@ void PrepareDoubleTeamAnim(u32 taskId, u32 animBattler, bool32 forAllySwitch) gSprites[spriteId].sBattlerFlank = (animBattler != ANIM_ATTACKER); else gSprites[spriteId].sBattlerFlank = (animBattler == ANIM_ATTACKER); - + // correct direction on opponent side if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_OPPONENT) gSprites[spriteId].sBattlerFlank ^= 1; - + gSprites[spriteId].callback = AnimDoubleTeam; task->tBlendSpritesCount++; } @@ -6603,7 +6603,7 @@ static void ReloadBattlerSprites(u32 battler, struct Pokemon *party) UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL); // If battler has an indicator for a gimmick, hide the sprite until the move animation finishes. UpdateIndicatorVisibilityAndType(gHealthboxSpriteIds[battler], TRUE); - + // Try to recreate shadow sprite if (gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId < MAX_SPRITES) { diff --git a/src/battle_anim_effects_2.c b/src/battle_anim_effects_2.c index 3324d276fdc8..b33c0a8bb652 100755 --- a/src/battle_anim_effects_2.c +++ b/src/battle_anim_effects_2.c @@ -1726,7 +1726,7 @@ void AnimTask_AirCutterProjectile(u8 taskId) attackerX = gTasks[taskId].data[9] = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X); attackerY = gTasks[taskId].data[10] = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y); - if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle() && IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimTarget))) { SetAverageBattlerPositions(gBattleAnimTarget, FALSE, &targetX, &targetY); @@ -3854,7 +3854,7 @@ static void AnimPerishSongMusicNote_Step2(struct Sprite *sprite) static void AnimGuardRing(struct Sprite *sprite) { - if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker))) + if (IsDoubleBattle() && IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker))) { SetAverageBattlerPositions(gBattleAnimAttacker, FALSE, &sprite->x, &sprite->y); sprite->y += 40; diff --git a/src/battle_anim_mons.c b/src/battle_anim_mons.c index 73c1e994489f..e0b482040988 100644 --- a/src/battle_anim_mons.c +++ b/src/battle_anim_mons.c @@ -17,8 +17,6 @@ #include "util.h" #include "constants/battle_anim.h" -#define IS_DOUBLE_BATTLE() ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) - extern const struct OamData gOamData_AffineNormal_ObjNormal_64x64; static void AnimTranslateLinear_WithFollowup_SetCornerVecX(struct Sprite *sprite); @@ -868,11 +866,6 @@ bool8 IsBattlerSpritePresent(u8 battlerId) } } -bool8 IsDoubleBattle(void) -{ - return IS_DOUBLE_BATTLE(); -} - #define BG_ANIM_PAL_1 8 #define BG_ANIM_PAL_2 9 #define BG_ANIM_PAL_CONTEST 14 diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index f023859b5940..e03ad2ace6c5 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -7250,7 +7250,7 @@ static u8 LoadBattleAnimTarget(u8 arg) { u8 battler; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { switch (gBattleAnimArgs[arg]) { @@ -7281,7 +7281,7 @@ static u8 LoadBattleAnimTarget(u8 arg) static u8 GetProperCentredCoord(u8 battler, u8 coordType) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) return (GetBattlerSpriteCoord2(battler, coordType) + GetBattlerSpriteCoord2(BATTLE_PARTNER(battler), coordType)) / 2; return GetBattlerSpriteCoord(battler, coordType); @@ -7471,14 +7471,14 @@ static void SpriteCB_SpriteToCentreOfSide(struct Sprite *sprite) if (gBattleAnimArgs[2] == 0) //Attacker { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) InitSpritePosToAnimAttackersCentre(sprite, var); else InitSpritePosToAnimAttacker(sprite, var); } else { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) InitSpritePosToAnimTargetsCentre(sprite, var); else InitSpritePosToAnimTarget(sprite, var); @@ -7562,7 +7562,7 @@ static void SpriteCB_GrowingSuperpower(struct Sprite *sprite) static void SpriteCB_CentredSpiderWeb(struct Sprite *sprite) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) InitSpritePosToAnimTargetsCentre(sprite, FALSE); else InitSpritePosToAnimTarget(sprite, FALSE); @@ -7576,14 +7576,14 @@ static void SpriteCB_CoreEnforcerHits(struct Sprite *sprite) if (gBattleAnimArgs[2] == 0) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) InitSpritePosToAnimAttackersCentre(sprite, FALSE); else InitSpritePosToAnimAttacker(sprite, FALSE); } else { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) InitSpritePosToAnimTargetsCentre(sprite, FALSE); else InitSpritePosToAnimTarget(sprite, FALSE); @@ -7595,7 +7595,7 @@ static void SpriteCB_CoreEnforcerHits(struct Sprite *sprite) static void SpriteCB_CoreEnforcerBeam(struct Sprite *sprite) { - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!IsDoubleBattle()) { AnimSolarBeamBigOrb(sprite); } @@ -7867,14 +7867,14 @@ void SpriteCB_RandomCentredHits(struct Sprite *sprite) if (gBattleAnimArgs[0] == 0) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) InitSpritePosToAnimAttackersCentre(sprite, FALSE); else InitSpritePosToAnimAttacker(sprite, FALSE); } else { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) InitSpritePosToAnimTargetsCentre(sprite, FALSE); else InitSpritePosToAnimTarget(sprite, FALSE); @@ -8179,7 +8179,7 @@ static void SpriteCB_BeamUpStep(struct Sprite *sprite) static void SpriteCB_CentredElectricity(struct Sprite *sprite) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) InitSpritePosToAnimTargetsCentre(sprite, FALSE); else InitSpritePosToAnimTarget(sprite, FALSE); diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index a5dc6f3af137..b555711933a9 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -581,7 +581,7 @@ static void OpponentHandleChooseMove(u32 battler) if (GetBattlerMoveTargetType(battler, move) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (battler << 8)); - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + else if (IsDoubleBattle()) { do { target = GetBattlerAtPosition(Random() & 2); @@ -653,7 +653,7 @@ static void OpponentHandleChoosePokemon(u32 battler) { s32 battler1, battler2, firstId, lastId; - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!IsDoubleBattle()) { battler2 = battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); } diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 5dae29563dd5..8760252c67ef 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -44,6 +44,7 @@ #include "level_caps.h" #include "menu.h" #include "pokemon_summary_screen.h" +#include "type_icons.h" static void PlayerBufferExecCompleted(u32 battler); static void PlayerHandleLoadMonSprite(u32 battler); @@ -59,7 +60,6 @@ static void PlayerHandlePrintString(u32 battler); static void PlayerHandlePrintSelectionString(u32 battler); static void PlayerHandleChooseAction(u32 battler); static void PlayerHandleYesNoBox(u32 battler); -static void PlayerHandleChooseMove(u32 battler); static void PlayerHandleChooseItem(u32 battler); static void PlayerHandleChoosePokemon(u32 battler); static void PlayerHandleCmd23(u32 battler); @@ -81,14 +81,11 @@ static void PlayerHandleEndLinkBattle(u32 battler); static void PlayerHandleBattleDebug(u32 battler); static void PlayerBufferRunCommand(u32 battler); -static void HandleInputChooseTarget(u32 battler); -static void HandleInputChooseMove(u32 battler); static void MoveSelectionDisplayPpNumber(u32 battler); static void MoveSelectionDisplayPpString(u32 battler); static void MoveSelectionDisplayMoveType(u32 battler); static void MoveSelectionDisplayMoveNames(u32 battler); static void MoveSelectionDisplayMoveDescription(u32 battler); -static void HandleMoveSwitching(u32 battler); static void SwitchIn_HandleSoundAndEnd(u32 battler); static void WaitForMonSelection(u32 battler); static void CompleteWhenChoseItem(u32 battler); @@ -382,7 +379,7 @@ static void HandleInputChooseAction(u32 battler) } else if (JOY_NEW(B_BUTTON) || gPlayerDpadHoldFrames > 59) { - if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle() && GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT && !(gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)]) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) @@ -426,7 +423,7 @@ static void HandleInputChooseAction(u32 battler) } } -static void HandleInputChooseTarget(u32 battler) +void HandleInputChooseTarget(u32 battler) { s32 i; static const u8 identities[MAX_BATTLERS_COUNT] = {B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_RIGHT, B_POSITION_OPPONENT_LEFT}; @@ -662,7 +659,7 @@ static void TryShowAsTarget(u32 battler) } } -static void HandleInputChooseMove(u32 battler) +void HandleInputChooseMove(u32 battler) { u16 moveTarget; u32 canSelectTarget = 0; @@ -968,7 +965,7 @@ static u32 UNUSED HandleMoveInputUnused(u32 battler) return var; } -static void HandleMoveSwitching(u32 battler) +void HandleMoveSwitching(u32 battler) { u8 perMovePPBonuses[MAX_MON_MOVES]; struct ChooseMoveStruct moveStruct; @@ -1757,7 +1754,7 @@ static void MoveSelectionDisplayMoveType(u32 battler) } else { - end = StringCopy(txtPtr, gTypesInfo[type].name); + end = StringCopy(txtPtr, gTypesInfo[type].name); } PrependFontIdToFit(txtPtr, end, FONT_NORMAL, WindowWidthPx(B_WIN_MOVE_TYPE) - 25); @@ -2075,7 +2072,7 @@ static void PlayerHandleYesNoBox(u32 battler) } } -static void HandleChooseMoveAfterDma3(u32 battler) +void HandleChooseMoveAfterDma3(u32 battler) { if (!IsDma3ManagerBusyWithBgCopy()) { @@ -2097,7 +2094,7 @@ static void PlayerChooseMoveInBattlePalace(u32 battler) } } -static void PlayerHandleChooseMove(u32 battler) +void PlayerHandleChooseMove(u32 battler) { if (gBattleTypeFlags & BATTLE_TYPE_PALACE) { @@ -2125,6 +2122,7 @@ static void PlayerHandleChooseMove(u32 battler) void InitMoveSelectionsVarsAndStrings(u32 battler) { + LoadTypeIcons(battler); MoveSelectionDisplayMoveNames(battler); gMultiUsePlayerCursor = 0xFF; MoveSelectionCreateCursorAt(gMoveSelectionCursor[battler], 0); diff --git a/src/battle_controllers.c b/src/battle_controllers.c index fae42939d0f8..e11406831b24 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -175,7 +175,7 @@ static void InitSinglePlayerBtlControllers(void) gBattlerPartyIndexes[3] = 3; } } - else if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + else if (!IsDoubleBattle()) { gBattleMainFunc = BeginBattleIntro; @@ -417,7 +417,7 @@ static void InitLinkBtlControllers(void) s32 i; u8 multiplayerId; - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!IsDoubleBattle()) { if (gBattleTypeFlags & BATTLE_TYPE_IS_MASTER) { @@ -442,7 +442,7 @@ static void InitLinkBtlControllers(void) gBattlersCount = 2; } } - else if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) && gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + else if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) && IsDoubleBattle()) { if (gBattleTypeFlags & BATTLE_TYPE_IS_MASTER) { @@ -610,7 +610,7 @@ static void InitLinkBtlControllers(void) bool32 IsValidForBattle(struct Pokemon *mon) { u32 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG); - return (species != SPECIES_NONE + return (species != SPECIES_NONE && species != SPECIES_EGG && GetMonData(mon, MON_DATA_HP) != 0 && GetMonData(mon, MON_DATA_IS_EGG) == FALSE); diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index cb3349ee3256..b396f1d7b555 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -309,7 +309,7 @@ static u8 GetBattlePalaceMoveGroup(u8 battler, u16 move) static u16 GetBattlePalaceTarget(u32 battler) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { u8 opposing1, opposing2; diff --git a/src/battle_gimmick.c b/src/battle_gimmick.c index c8ee93221862..2595e4cbdade 100644 --- a/src/battle_gimmick.c +++ b/src/battle_gimmick.c @@ -96,7 +96,7 @@ bool32 ShouldTrainerBattlerUseGimmick(u32 battler, enum Gimmick gimmick) bool32 HasTrainerUsedGimmick(u32 battler, enum Gimmick gimmick) { // Check whether partner battler has used gimmick or plans to during turn. - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + if (IsDoubleBattle() && IsPartnerMonFromSameTrainer(battler) && (gBattleStruct->gimmick.activated[BATTLE_PARTNER(battler)][gimmick] || ((gBattleStruct->gimmick.toActivate & gBitTable[BATTLE_PARTNER(battler)] @@ -115,7 +115,7 @@ bool32 HasTrainerUsedGimmick(u32 battler, enum Gimmick gimmick) void SetGimmickAsActivated(u32 battler, enum Gimmick gimmick) { gBattleStruct->gimmick.activated[battler][gimmick] = TRUE; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsPartnerMonFromSameTrainer(battler)) + if (IsDoubleBattle() && IsPartnerMonFromSameTrainer(battler)) gBattleStruct->gimmick.activated[BATTLE_PARTNER(battler)][gimmick] = TRUE; } @@ -155,7 +155,7 @@ void CreateGimmickTriggerSprite(u32 battler) if (gBattleStruct->gimmick.triggerSpriteId == 0xFF) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) gBattleStruct->gimmick.triggerSpriteId = CreateSprite(gimmick->triggerTemplate, gSprites[gHealthboxSpriteIds[battler]].x - DOUBLES_GIMMICK_TRIGGER_POS_X_SLIDE, gSprites[gHealthboxSpriteIds[battler]].y - DOUBLES_GIMMICK_TRIGGER_POS_Y_DIFF, 0); @@ -204,7 +204,7 @@ static void SpriteCb_GimmickTrigger(struct Sprite *sprite) s32 xSlide, xPriority, xOptimal; s32 yDiff; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { xSlide = DOUBLES_GIMMICK_TRIGGER_POS_X_SLIDE; xPriority = DOUBLES_GIMMICK_TRIGGER_POS_X_PRIORITY; diff --git a/src/battle_main.c b/src/battle_main.c index 23047107b8e7..54da8223afda 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4136,7 +4136,7 @@ void SwitchPartyOrder(u32 battler) partyId2 = GetPartyIdFromBattlePartyId(*(gBattleStruct->monToSwitchIntoId + battler)); SwitchPartyMonSlots(partyId1, partyId2); - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++) { @@ -4277,7 +4277,7 @@ static void HandleTurnActionSelectionState(void) i); } - BtlController_EmitChooseMove(battler, BUFFER_A, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0, FALSE, &moveInfo); + BtlController_EmitChooseMove(battler, BUFFER_A, IsDoubleBattle() != 0, FALSE, &moveInfo); MarkBattlerForControllerExec(battler); } break; @@ -4570,7 +4570,7 @@ static void HandleTurnActionSelectionState(void) else i = FALSE; - if (((gBattleTypeFlags & BATTLE_TYPE_MULTI) || !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (((gBattleTypeFlags & BATTLE_TYPE_MULTI) || !IsDoubleBattle()) || (position & BIT_FLANK) != B_FLANK_LEFT || (*(&gBattleStruct->absentBattlerFlags) & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(position))])) { diff --git a/src/battle_message.c b/src/battle_message.c index 87ac5326fb8f..b1c536b8655c 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -2826,7 +2826,7 @@ void BufferStringBattle(u16 stringID, u32 battler) { if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY) stringPtr = sText_LegendaryPkmnAppeared; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]])) + else if (IsDoubleBattle() && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]])) stringPtr = sText_TwoWildPkmnAppeared; else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) stringPtr = sText_WildPkmnAppearedPause; @@ -2837,7 +2837,7 @@ void BufferStringBattle(u16 stringID, u32 battler) case STRINGID_INTROSENDOUT: // poke first send-out if (GetBattlerSide(battler) == B_SIDE_PLAYER) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]])) + if (IsDoubleBattle() && IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]])) { if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) stringPtr = sText_InGamePartnerSentOutZGoN; @@ -2855,7 +2855,7 @@ void BufferStringBattle(u16 stringID, u32 battler) } else { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]])) + if (IsDoubleBattle() && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]])) { if (BATTLE_TWO_VS_ONE_OPPONENT) stringPtr = sText_Trainer1SentOutTwoPkmn; @@ -2886,7 +2886,7 @@ void BufferStringBattle(u16 stringID, u32 battler) { if (*(&gBattleStruct->hpScale) == 0) stringPtr = sText_PkmnThatsEnough; - else if (*(&gBattleStruct->hpScale) == 1 || gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + else if (*(&gBattleStruct->hpScale) == 1 || IsDoubleBattle()) stringPtr = sText_PkmnComeBack; else if (*(&gBattleStruct->hpScale) == 2) stringPtr = sText_PkmnOkComeBack; @@ -2911,7 +2911,7 @@ void BufferStringBattle(u16 stringID, u32 battler) case STRINGID_SWITCHINMON: // switch-in msg if (GetBattlerSide(gBattleScripting.battler) == B_SIDE_PLAYER) { - if (*(&gBattleStruct->hpScale) == 0 || gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (*(&gBattleStruct->hpScale) == 0 || IsDoubleBattle()) stringPtr = sText_GoPkmn2; else if (*(&gBattleStruct->hpScale) == 1) stringPtr = sText_DoItPkmn; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 575e1cd043ce..396521f5a0a2 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1752,7 +1752,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u return; } - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && + if (IsDoubleBattle() && (moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY)) gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_ATK; else @@ -2498,7 +2498,7 @@ static void Cmd_resultmessage(void) if (gMoveResultFlags & MOVE_RESULT_MISSED && (!(gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) || gBattleCommunication[MISS_TYPE] > B_MSG_AVOIDED_ATK)) { if (gBattleCommunication[MISS_TYPE] > B_MSG_AVOIDED_ATK) // Wonder Guard or Levitate - show the ability pop-up - CreateAbilityPopUp(gBattlerTarget, gBattleMons[gBattlerTarget].ability, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0); + CreateAbilityPopUp(gBattlerTarget, gBattleMons[gBattlerTarget].ability, (IsDoubleBattle()) != 0); stringId = gMissStringIds[gBattleCommunication[MISS_TYPE]]; gBattleCommunication[MSG_DISPLAY] = 1; } @@ -4352,7 +4352,7 @@ static void Cmd_getexp(void) { // Music change in a wild battle after fainting opposing pokemon. if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) - && (gBattleMons[0].hp || (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattleMons[2].hp)) + && (gBattleMons[0].hp || (IsDoubleBattle() && gBattleMons[2].hp)) && !IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)) && !IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)) && !gBattleStruct->wildVictorySong) @@ -4403,7 +4403,7 @@ static void Cmd_getexp(void) } // get exp getter battler - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { if (gBattlerPartyIndexes[2] == *expMonId && !(gAbsentBattlerFlags & gBitTable[2])) gBattleStruct->expGetterBattlerId = 2; @@ -4483,7 +4483,7 @@ static void Cmd_getexp(void) // update battle mon structure after level up if (gBattlerPartyIndexes[0] == *expMonId && gBattleMons[0].hp) battler = 0; - else if (gBattlerPartyIndexes[2] == *expMonId && gBattleMons[2].hp && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + else if (gBattlerPartyIndexes[2] == *expMonId && gBattleMons[2].hp && (IsDoubleBattle())) battler = 2; if (battler != 0xFF) @@ -5919,7 +5919,7 @@ static void Cmd_moveend(void) gBattleStruct->targetsDone[gBattlerAttacker] |= gBitTable[gBattlerTarget]; if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && IsDoubleBattle() && !gProtectStructs[gBattlerAttacker].chargingTurn && (moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY) @@ -6689,7 +6689,7 @@ bool32 CanBattlerSwitch(u32 battler) { battlerIn1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) battlerIn2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); else battlerIn2 = battlerIn1; @@ -6701,7 +6701,7 @@ bool32 CanBattlerSwitch(u32 battler) // Check if attacker side has mon to switch into battlerIn1 = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) battlerIn2 = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); else battlerIn2 = battlerIn1; @@ -6765,7 +6765,7 @@ static void Cmd_openpartyscreen(void) if (cmd->battler == BS_FAINTED_MULTIPLE_1) { - if ((gBattleTypeFlags & BATTLE_TYPE_MULTI) || !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if ((gBattleTypeFlags & BATTLE_TYPE_MULTI) || !(IsDoubleBattle())) { for (battler = 0; battler < gBattlersCount; battler++) { @@ -6791,7 +6791,7 @@ static void Cmd_openpartyscreen(void) } } } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + else if (IsDoubleBattle()) { bool8 hasReplacement_0, hasReplacement_1, hasReplacement_2, hasReplacement_3; @@ -6922,7 +6922,7 @@ static void Cmd_openpartyscreen(void) { if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { hitmarkerFaintBits = gHitMarker >> 28; if (gBitTable[2] & hitmarkerFaintBits && gBitTable[0] & hitmarkerFaintBits) @@ -7466,7 +7466,7 @@ static void Cmd_handlelearnnewmove(void) { GiveMoveToBattleMon(&gBattleMons[battler], learnMove); } - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { battler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); if (gBattlerPartyIndexes[battler] == monId @@ -7572,7 +7572,7 @@ static void Cmd_yesnoboxlearnmove(void) RemoveBattleMonPPBonus(&gBattleMons[0], movePosition); SetBattleMonMoveSlot(&gBattleMons[0], gMoveToLearn, movePosition); } - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + if (IsDoubleBattle() && gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId && MOVE_IS_PERMANENT(2, movePosition)) { @@ -7686,7 +7686,7 @@ static u32 GetTrainerMoneyToGive(u16 trainerId) if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * trainerMoney; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + else if (IsDoubleBattle()) moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * 2 * trainerMoney; else moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * trainerMoney; @@ -8352,7 +8352,7 @@ static bool32 IsMonGettingExpSentOut(void) { if (gBattlerPartyIndexes[0] == gBattleStruct->expGetterMonId) return TRUE; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId) + if (IsDoubleBattle() && gBattlerPartyIndexes[2] == gBattleStruct->expGetterMonId) return TRUE; return FALSE; @@ -8425,7 +8425,7 @@ static void Cmd_hpthresholds(void) { CMD_ARGS(u8 battler); - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!(IsDoubleBattle())) { u32 battler = GetBattlerForBattleScript(cmd->battler); u32 opposingBattler = BATTLE_OPPOSITE(battler); @@ -8451,7 +8451,7 @@ static void Cmd_hpthresholds2(void) { CMD_ARGS(u8 battler); - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!(IsDoubleBattle())) { u32 battler = GetBattlerForBattleScript(cmd->battler); u32 opposingBattler = BATTLE_OPPOSITE(battler); @@ -9931,7 +9931,7 @@ static void Cmd_various(void) case VARIOUS_ABILITY_POPUP: { VARIOUS_ARGS(); - CreateAbilityPopUp(battler, gBattleMons[battler].ability, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0); + CreateAbilityPopUp(battler, gBattleMons[battler].ability, (IsDoubleBattle()) != 0); break; } case VARIOUS_UPDATE_ABILITY_POPUP: @@ -10125,7 +10125,7 @@ static void Cmd_various(void) gSideTimers[GetBattlerSide(battler)].auroraVeilTimer = 5; gSideTimers[GetBattlerSide(battler)].auroraVeilBattlerId = battler; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) + if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) gBattleCommunication[MULTISTRING_CHOOSER] = 5; else gBattleCommunication[MULTISTRING_CHOOSER] = 5; @@ -10301,7 +10301,7 @@ static void Cmd_various(void) case VARIOUS_JUMP_IF_TEAM_HEALTHY: { VARIOUS_ARGS(const u8 *jumpInstr); - if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && IsBattlerAlive(BATTLE_PARTNER(battler))) + if ((IsDoubleBattle()) && IsBattlerAlive(BATTLE_PARTNER(battler))) { u8 partner = BATTLE_PARTNER(battler); if ((gBattleMons[battler].hp == gBattleMons[battler].maxHP && !(gBattleMons[battler].status1 & STATUS1_ANY)) @@ -10914,7 +10914,7 @@ static void Cmd_various(void) PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(&party[gSelectedMonPartyId], MON_DATA_SPECIES)); // If an on-field battler is revived, it needs to be sent out again. - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && + if (IsDoubleBattle() && gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)] == gSelectedMonPartyId) { gBattleScripting.battler = BATTLE_PARTNER(gBattlerAttacker); @@ -11233,7 +11233,7 @@ static void Cmd_setreflect(void) gSideTimers[GetBattlerSide(gBattlerAttacker)].reflectTimer = 5; gSideTimers[GetBattlerSide(gBattlerAttacker)].reflectBattlerId = gBattlerAttacker; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) + if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_REFLECT_DOUBLE; else gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_REFLECT_SINGLE; @@ -12097,7 +12097,7 @@ static void Cmd_forcerandomswitch(void) battler2PartyId = gBattlerPartyIndexes[gBattlerTarget]; battler1PartyId = gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerTarget)]; } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + else if (IsDoubleBattle()) { firstMonId = 0; lastMonId = PARTY_SIZE; @@ -12295,7 +12295,7 @@ static void Cmd_setlightscreen(void) gSideTimers[GetBattlerSide(gBattlerAttacker)].lightscreenTimer = 5; gSideTimers[GetBattlerSide(gBattlerAttacker)].lightscreenBattlerId = gBattlerAttacker; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) + if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_LIGHTSCREEN_DOUBLE; else gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_LIGHTSCREEN_SINGLE; @@ -12465,7 +12465,7 @@ static void Cmd_updatestatusicon(void) BtlController_EmitStatusIconUpdate(battler, BUFFER_A, gBattleMons[battler].status1, gBattleMons[battler].status2); MarkBattlerForControllerExec(battler); } - if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if ((IsDoubleBattle())) { battler = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); if (!(gAbsentBattlerFlags & gBitTable[battler])) @@ -12502,7 +12502,7 @@ static void Cmd_setfocusenergy(void) CMD_ARGS(u8 battler); u8 battler = GetBattlerForBattleScript(cmd->battler); - if ((gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_CHEER && (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || (gAbsentBattlerFlags & gBitTable[battler]))) + if ((gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_CHEER && (!(IsDoubleBattle()) || (gAbsentBattlerFlags & gBitTable[battler]))) || gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) { gMoveResultFlags |= MOVE_RESULT_FAILED; @@ -13245,7 +13245,7 @@ static void Cmd_healpartystatus(void) gBattleMons[gBattlerAttacker].status1 = 0; gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + if (IsDoubleBattle() && !(gAbsentBattlerFlags & gBitTable[partner])) { gBattleMons[partner].status1 = 0; @@ -14088,7 +14088,7 @@ static void Cmd_trysethelpinghand(void) gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + if (IsDoubleBattle() && !(gAbsentBattlerFlags & gBitTable[gBattlerTarget]) && !gProtectStructs[gBattlerAttacker].helpingHand && !gProtectStructs[gBattlerTarget].helpingHand) @@ -14910,7 +14910,7 @@ static void Cmd_pursuitdoubles(void) u32 battler = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + if (IsDoubleBattle() && !(gAbsentBattlerFlags & gBitTable[battler]) && gChosenActionByBattler[battler] == B_ACTION_USE_MOVE && gMovesInfo[gChosenMoveByBattler[battler]].effect == EFFECT_PURSUIT) @@ -15908,7 +15908,7 @@ bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler) && gMovesInfo[move].strikeCount < 2 && gMovesInfo[move].effect != EFFECT_MULTI_HIT) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { switch (GetBattlerMoveTargetType(battler, move)) { @@ -16025,7 +16025,7 @@ void BS_SetZEffect(void) static void TryUpdateRoundTurnOrder(void) { - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { u32 i; u32 j = 0; @@ -16163,8 +16163,7 @@ void BS_ItemRestoreHP(void) // Check if the recipient is an active battler. if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker]) battler = gBattlerAttacker; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)]) + else if (IsDoubleBattle() && gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)]) battler = BATTLE_PARTNER(gBattlerAttacker); // Get amount to heal. @@ -16201,7 +16200,7 @@ void BS_ItemRestoreHP(void) SetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_HP, &hp); // Revived battlers on the field need to be brought back. - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && battler != MAX_BATTLERS_COUNT) + if (IsDoubleBattle() && battler != MAX_BATTLERS_COUNT) { gAbsentBattlerFlags &= ~gBitTable[battler]; gBattleMons[battler].hp = hp; @@ -16227,7 +16226,7 @@ void BS_ItemCureStatus(void) previousStatus2 = gBattleMons[battler].status2; gBattleMons[gBattlerAttacker].status2 &= ~GetItemStatus2Mask(gLastUsedItem); } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + else if (IsDoubleBattle() && gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)]) { battler = BATTLE_PARTNER(gBattlerAttacker); @@ -16292,7 +16291,7 @@ void BS_ItemRestorePP(void) // Check if the recipient is an active battler. if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker]) battler = gBattlerAttacker; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + else if (IsDoubleBattle() && gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)]) battler = BATTLE_PARTNER(gBattlerAttacker); @@ -16623,7 +16622,7 @@ void BS_SetPledge(void) gBattleCommunication[MSG_DISPLAY] = 0; } else if ((gChosenActionByBattler[partner] == B_ACTION_USE_MOVE) - && gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && IsDoubleBattle() && IsBattlerAlive(partner) && gCurrentMove != partnerMove && gMovesInfo[partnerMove].effect == EFFECT_PLEDGE) diff --git a/src/battle_terastal.c b/src/battle_terastal.c index 6866c6aaad87..c0540f5aa37c 100644 --- a/src/battle_terastal.c +++ b/src/battle_terastal.c @@ -30,7 +30,7 @@ void ActivateTera(u32 battler) if (B_FLAG_TERA_ORB_CHARGED != 0 && (B_FLAG_TERA_ORB_NO_COST == 0 || !FlagGet(B_FLAG_TERA_ORB_NO_COST)) && side == B_SIDE_PLAYER - && !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !IsPartnerMonFromSameTrainer(battler))) + && !(IsDoubleBattle() && !IsPartnerMonFromSameTrainer(battler))) { FlagClear(B_FLAG_TERA_ORB_CHARGED); } diff --git a/src/battle_util.c b/src/battle_util.c index 3d9338acee60..24095c08ed14 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -221,7 +221,7 @@ void HandleAction_UseMove(void) { gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = gSideTimers[side].followmeTarget; // follow me moxie fix } - else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + else if (IsDoubleBattle() && gSideTimers[side].followmeTimer == 0 && (gMovesInfo[gCurrentMove].power != 0 || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS)) && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) @@ -305,8 +305,7 @@ void HandleAction_UseMove(void) gBattlerTarget = battler; } } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && moveTarget & MOVE_TARGET_RANDOM) + else if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM) { if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) { @@ -336,8 +335,7 @@ void HandleAction_UseMove(void) else gBattlerTarget = gBattlerAttacker; } - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE - && moveTarget == MOVE_TARGET_FOES_AND_ALLY) + else if (IsDoubleBattle() && moveTarget == MOVE_TARGET_FOES_AND_ALLY) { for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) { @@ -3744,7 +3742,7 @@ bool32 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2 u32 i, side, playerId, flankId; struct Pokemon *party; - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!IsDoubleBattle()) return FALSE; side = GetBattlerSide(battler); @@ -4328,7 +4326,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 target1 = GetBattlerAtPosition(side); target2 = GetBattlerAtPosition(side + BIT_FLANK); gSpecialStatuses[battler].switchInAbilityDone = TRUE; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { if (!gAbilitiesInfo[gBattleMons[target1].ability].cantBeTraced && gBattleMons[target1].hp != 0 && !gAbilitiesInfo[gBattleMons[target2].ability].cantBeTraced && gBattleMons[target2].hp != 0) @@ -5177,7 +5175,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE) && !(IS_MOVE_STATUS(move) && (gLastUsedAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove))) { - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) + if (!IsDoubleBattle() || !(moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) CancelMultiTurnMoves(gBattlerAttacker); // Don't cancel moves that can hit two targets bc one target might not be protected gBattleScripting.battler = gBattlerAbility = gBattlerTarget; battleScriptBlocksMove = BattleScript_DarkTypePreventsPrankster; @@ -8252,7 +8250,7 @@ u32 SetRandomTarget(u32 battler) [B_SIDE_OPPONENT] = {B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT}, }; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { target = GetBattlerAtPosition(targets[GetBattlerSide(battler)][Random() % 2]); if (!IsBattlerAlive(target)) @@ -8317,7 +8315,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget) side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker)); if (IsAffectedByFollowMe(gBattlerAttacker, side, move)) targetBattler = gSideTimers[side].followmeTarget; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM) + else if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM) targetBattler = SetRandomTarget(gBattlerAttacker); else targetBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker))); @@ -9983,7 +9981,7 @@ static inline uq4_12_t GetScreensModifier(u32 move, u32 battlerAtk, u32 battlerD if (isCrit || abilityAtk == ABILITY_INFILTRATOR || gProtectStructs[battlerAtk].confusionSelfDmg) return UQ_4_12(1.0); if (reflect || lightScreen || auroraVeil) - return (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) ? UQ_4_12(0.667) : UQ_4_12(0.5); + return (IsDoubleBattle()) ? UQ_4_12(0.667) : UQ_4_12(0.5); return UQ_4_12(1.0); } @@ -11787,7 +11785,7 @@ void SetShellSideArmCategory(void) bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef) { - return (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + return (IsDoubleBattle() && IsBattlerAlive(BATTLE_PARTNER(battlerDef)) && battlerDef != BATTLE_PARTNER(battlerAtk)); } diff --git a/src/battle_util2.c b/src/battle_util2.c index 2c333978d240..326acf0e40a8 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -80,7 +80,7 @@ void AdjustFriendshipOnBattleFaint(u8 battler) { u8 opposingBattlerId; - if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + if (IsDoubleBattle()) { u8 opposingBattlerId2; diff --git a/src/data/types_info.h b/src/data/types_info.h index f9bd233ca6c4..df74199bdd1d 100644 --- a/src/data/types_info.h +++ b/src/data/types_info.h @@ -60,6 +60,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB_WHITE, .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_NormalTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = TRUE, }, [TYPE_NORMAL] = { @@ -71,6 +73,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB_WHITE, // custom .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_NormalTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_SILK_SCARF, //.berry = ITEM_CHILAN_BERRY, //.gem = ITEM_NORMAL_GEM, @@ -88,6 +92,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(26, 8, 14), .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_FightingTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_BLACK_BELT, //.berry = ITEM_CHOPLE_BERRY, //.gem = ITEM_FIGHTING_GEM, @@ -107,6 +113,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(31, 26, 7), .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_FlyingTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_SHARP_BEAK, //.berry = ITEM_COBA_BERRY, //.gem = ITEM_FLYING_GEM, @@ -126,6 +134,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(26, 10, 25), // custom .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_PoisonTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_POISON_BARB, //.berry = ITEM_KEBIA_BERRY, //.gem = ITEM_POISON_GEM, @@ -145,6 +155,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(25, 23, 18), .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_GroundTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_SOFT_SAND, //.berry = ITEM_SHUCA_BERRY, //.gem = ITEM_GROUND_GEM, @@ -164,6 +176,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(18, 16, 8), // custom .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_RockTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_HARD_STONE, //.berry = ITEM_CHARTI_BERRY, //.gem = ITEM_ROCK_GEM, @@ -183,6 +197,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(18, 24, 6), .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_BugTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_SILVER_POWDER, //.berry = ITEM_TANGA_BERRY, //.gem = ITEM_BUG_GEM, @@ -202,6 +218,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(12, 10, 16), .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_GhostTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_SPELL_TAG, //.berry = ITEM_KASIB_BERRY, //.gem = ITEM_GHOST_GEM, @@ -221,6 +239,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(19, 19, 20), .damageCategory = DAMAGE_CATEGORY_PHYSICAL, .paletteTMHM = gItemIconPalette_SteelTMHM, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_METAL_COAT, //.berry = ITEM_BABIRI_BERRY, //.gem = ITEM_STEEL_GEM, @@ -237,6 +257,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 15, .teraTypeRGBValue = RGB_WHITE, .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = TRUE, }, [TYPE_FIRE] = { @@ -248,6 +270,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(31, 20, 11), .damageCategory = DAMAGE_CATEGORY_SPECIAL, .paletteTMHM = gItemIconPalette_FireTMHM, + .useSecondTypeIconPalette = TRUE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_CHARCOAL, //.berry = ITEM_OCCA_BERRY, //.gem = ITEM_FIRE_GEM, @@ -267,6 +291,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(10, 18, 27), .damageCategory = DAMAGE_CATEGORY_SPECIAL, .paletteTMHM = gItemIconPalette_WaterTMHM, + .useSecondTypeIconPalette = TRUE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_MYSTIC_WATER, //.berry = ITEM_PASSHO_BERRY, //.gem = ITEM_WATER_GEM, @@ -286,6 +312,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(12, 24, 11), .damageCategory = DAMAGE_CATEGORY_SPECIAL, .paletteTMHM = gItemIconPalette_GrassTMHM, + .useSecondTypeIconPalette = TRUE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_MIRACLE_SEED, //.berry = ITEM_RINDO_BERRY, //.gem = ITEM_GRASS_GEM, @@ -305,6 +333,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(30, 26, 7), .damageCategory = DAMAGE_CATEGORY_SPECIAL, .paletteTMHM = gItemIconPalette_ElectricTMHM, + .useSecondTypeIconPalette = TRUE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_MAGNET, //.berry = ITEM_WACAN_BERRY, //.gem = ITEM_ELECTRIC_GEM, @@ -324,6 +354,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(31, 14, 15), .damageCategory = DAMAGE_CATEGORY_SPECIAL, .paletteTMHM = gItemIconPalette_PsychicTMHM, + .useSecondTypeIconPalette = TRUE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_TWISTED_SPOON, //.berry = ITEM_PAYAPA_BERRY, //.gem = ITEM_PSYCHIC_GEM, @@ -343,6 +375,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(14, 26, 25), .damageCategory = DAMAGE_CATEGORY_SPECIAL, .paletteTMHM = gItemIconPalette_IceTMHM, + .useSecondTypeIconPalette = TRUE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_NEVER_MELT_ICE, //.berry = ITEM_YACHE_BERRY, //.gem = ITEM_ICE_GEM, @@ -362,6 +396,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(10, 18, 27), .damageCategory = DAMAGE_CATEGORY_SPECIAL, .paletteTMHM = gItemIconPalette_DragonTMHM, + .useSecondTypeIconPalette = TRUE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_DRAGON_FANG, //.berry = ITEM_HABAN_BERRY, //.gem = ITEM_DRAGON_GEM, @@ -381,6 +417,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(6, 5, 8), .damageCategory = DAMAGE_CATEGORY_SPECIAL, .paletteTMHM = gItemIconPalette_DarkTMHM, + .useSecondTypeIconPalette = TRUE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_BLACK_GLASSES, //.berry = ITEM_COLBUR_BERRY, //.gem = ITEM_DARK_GEM, @@ -400,6 +438,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .teraTypeRGBValue = RGB(31, 15, 21), .damageCategory = DAMAGE_CATEGORY_SPECIAL, .paletteTMHM = gItemIconPalette_FairyTMHM, + .useSecondTypeIconPalette = TRUE, + .isSpecialCaseType = FALSE, //.enhanceItem = ITEM_FAIRY_FEATHER, //.berry = ITEM_ROSELI_BERRY, //.gem = ITEM_FAIRY_GEM, @@ -418,6 +458,8 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .maxMove = MOVE_MAX_STRIKE, .teraTypeRGBValue = RGB(10, 18, 27), .paletteTMHM = gItemIconPalette_NormalTMHM, // failsafe + .useSecondTypeIconPalette = FALSE, + .isSpecialCaseType = TRUE, // .teraShard = ITEM_STELLAR_TERA_SHARD, }, }; diff --git a/src/graphics.c b/src/graphics.c index c35cec3467e2..9fb07715756e 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -2048,3 +2048,9 @@ const u16 gFrontierPassCancelButtonHighlighted_Tilemap[] = INCBIN_U16("graphics/ const u16 gBerryCrush_Crusher_Pal[] = INCBIN_U16("graphics/berry_crush/crusher.gbapal"); const u32 gBerryCrush_Crusher_Gfx[] = INCBIN_U32("graphics/berry_crush/crusher.4bpp.lz"); const u32 gBerryCrush_TextWindows_Tilemap[] = INCBIN_U32("graphics/berry_crush/text_windows.bin.lz"); + +const u32 gBattleIcons_Gfx1[] = INCBIN_U32("graphics/types/battle_icons1.4bpp.lz"); +const u32 gBattleIcons_Gfx2[] = INCBIN_U32("graphics/types/battle_icons2.4bpp.lz"); +const u32 gBattleIcons_Pal1[] = INCBIN_U32("graphics/types/battle_icons1.gbapal.lz"); +const u32 gBattleIcons_Pal2[] = INCBIN_U32("graphics/types/battle_icons2.gbapal.lz"); + diff --git a/src/party_menu.c b/src/party_menu.c index 5214ddc2be63..15433854a5a8 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -1353,7 +1353,7 @@ static void DrawCancelConfirmButtons(void) bool8 IsMultiBattle(void) { - if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gMain.inBattle) + if (gBattleTypeFlags & BATTLE_TYPE_MULTI && IsDoubleBattle() && gMain.inBattle) return TRUE; else return FALSE; diff --git a/src/pokemon.c b/src/pokemon.c index 78e19dfc8b84..cfb230712640 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -2100,7 +2100,7 @@ u8 GetDefaultMoveTarget(u8 battlerId) { u8 opposing = BATTLE_OPPOSITE(GetBattlerSide(battlerId)); - if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + if (!IsDoubleBattle()) return GetBattlerAtPosition(opposing); if (CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_BATTLER, battlerId) > 1) { diff --git a/src/tv.c b/src/tv.c index e0f910eaaf89..c0e207ce8a15 100644 --- a/src/tv.c +++ b/src/tv.c @@ -1262,7 +1262,7 @@ void PutBattleUpdateOnTheAir(u8 opponentLinkPlayerId, u16 move, u16 speciesPlaye if (gBattleTypeFlags & BATTLE_TYPE_MULTI) show->battleUpdate.battleType = 2; - else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + else if (IsDoubleBattle()) show->battleUpdate.battleType = 1; else show->battleUpdate.battleType = 0; diff --git a/src/type_icons.c b/src/type_icons.c new file mode 100644 index 000000000000..a36c3477759b --- /dev/null +++ b/src/type_icons.c @@ -0,0 +1,516 @@ +#include "global.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_controllers.h" +#include "battle_gimmick.h" +#include "decompress.h" +#include "graphics.h" +#include "pokedex.h" +#include "sprite.h" +#include "type_icons.h" + +static void LoadTypeSpritesAndPalettes(void); +static void LoadTypeIconsPerBattler(u32, u32); + +static bool32 UseDoubleBattleCoords(u32); + +static u32 GetMonPublicType(u32, u32); +static bool32 ShouldHideUncaughtType(u32); +static u32 GetMonDefensiveTeraType(struct Pokemon *, struct Pokemon*, u32, u32, u32, u32); +static u32 IsIllusionActiveAndTypeUnchanged(struct Pokemon*, u32, u32); + +static void CreateSpriteFromType(u32, bool32, u32[], u32, u32); +static bool32 ShouldSkipSecondType(u32[], u32); +static void SetTypeIconXY(s32*, s32*, u32, bool32, u32); + +static void CreateSpriteAndSetTypeSpriteAttributes(u32, u32 x, u32 y, u32, u32, bool32); +static bool32 ShouldFlipTypeIcon(bool32, u32, u32); + +static void SpriteCB_TypeIcon(struct Sprite*); +static void DestroyTypeIcon(struct Sprite*); +static bool32 ShouldHideTypeIcon(u32); +static s32 GetTypeIconHideMovement(bool32, u32); +static s32 GetTypeIconSlideMovement(bool32, u32, s32); +static s32 GetTypeIconBounceMovement(s32, u32); + +const struct Coords16 sTypeIconPositions[][2] = +{ + [B_POSITION_PLAYER_LEFT] = + { + [FALSE] = {221, 86}, + [TRUE] = {144, 71}, + }, + [B_POSITION_OPPONENT_LEFT] = + { + [FALSE] = {20, 26}, + [TRUE] = {97, 14}, + }, + [B_POSITION_PLAYER_RIGHT] = + { + [TRUE] = {156, 96}, + }, + [B_POSITION_OPPONENT_RIGHT] = + { + [TRUE] = {85, 39}, + }, +}; + +const union AnimCmd sSpriteAnim_TypeIcon_Normal[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_NORMAL), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Fighting[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_FIGHTING), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Flying[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_FLYING), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Poison[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_POISON), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Ground[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_GROUND), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Rock[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_ROCK), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Bug[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_BUG), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Ghost[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_GHOST), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Steel[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_STEEL), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Mystery[] = +{ + ANIMCMD_FRAME(TYPE_ICON_1_FRAME(TYPE_MYSTERY), 0), + ANIMCMD_END +}; + +const union AnimCmd sSpriteAnim_TypeIcon_Fire[] = +{ + ANIMCMD_FRAME(TYPE_ICON_2_FRAME(TYPE_FIRE), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Water[] = +{ + ANIMCMD_FRAME(TYPE_ICON_2_FRAME(TYPE_WATER), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Grass[] = +{ + ANIMCMD_FRAME(TYPE_ICON_2_FRAME(TYPE_GRASS), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Electric[] = +{ + ANIMCMD_FRAME(TYPE_ICON_2_FRAME(TYPE_ELECTRIC), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Psychic[] = +{ + ANIMCMD_FRAME(TYPE_ICON_2_FRAME(TYPE_PSYCHIC), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Ice[] = +{ + ANIMCMD_FRAME(TYPE_ICON_2_FRAME(TYPE_ICE), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Dragon[] = +{ + ANIMCMD_FRAME(TYPE_ICON_2_FRAME(TYPE_DRAGON), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Dark[] = +{ + ANIMCMD_FRAME(TYPE_ICON_2_FRAME(TYPE_DARK), 0), + ANIMCMD_END +}; +const union AnimCmd sSpriteAnim_TypeIcon_Fairy[] = +{ + ANIMCMD_FRAME(TYPE_ICON_2_FRAME(TYPE_FAIRY), 0), + ANIMCMD_END +}; + +const union AnimCmd *const sSpriteAnimTable_TypeIcons[] = +{ + [TYPE_NONE] = sSpriteAnim_TypeIcon_Mystery, + [TYPE_NORMAL] = sSpriteAnim_TypeIcon_Normal, + [TYPE_FIGHTING] = sSpriteAnim_TypeIcon_Fighting, + [TYPE_FLYING] = sSpriteAnim_TypeIcon_Flying, + [TYPE_POISON] = sSpriteAnim_TypeIcon_Poison, + [TYPE_GROUND] = sSpriteAnim_TypeIcon_Ground, + [TYPE_ROCK] = sSpriteAnim_TypeIcon_Rock, + [TYPE_BUG] = sSpriteAnim_TypeIcon_Bug, + [TYPE_GHOST] = sSpriteAnim_TypeIcon_Ghost, + [TYPE_STEEL] = sSpriteAnim_TypeIcon_Steel, + [TYPE_MYSTERY] = sSpriteAnim_TypeIcon_Mystery, + [TYPE_FIRE] = sSpriteAnim_TypeIcon_Fire, + [TYPE_WATER] = sSpriteAnim_TypeIcon_Water, + [TYPE_GRASS] = sSpriteAnim_TypeIcon_Grass, + [TYPE_ELECTRIC] = sSpriteAnim_TypeIcon_Electric, + [TYPE_PSYCHIC] = sSpriteAnim_TypeIcon_Psychic, + [TYPE_ICE] = sSpriteAnim_TypeIcon_Ice, + [TYPE_DRAGON] = sSpriteAnim_TypeIcon_Dragon, + [TYPE_DARK] = sSpriteAnim_TypeIcon_Dark, + [TYPE_FAIRY] = sSpriteAnim_TypeIcon_Fairy, + [TYPE_STELLAR] = sSpriteAnim_TypeIcon_Mystery, +}; + +const struct CompressedSpritePalette sTypeIconPal1 = +{ + .data = gBattleIcons_Pal1, + .tag = TYPE_ICON_TAG +}; + +const struct CompressedSpritePalette sTypeIconPal2 = +{ + .data = gBattleIcons_Pal2, + .tag = TYPE_ICON_TAG_2 +}; + +const struct OamData sOamData_TypeIcons = +{ + .affineMode = ST_OAM_AFFINE_OFF, + .objMode = ST_OAM_OBJ_NORMAL, + .shape = SPRITE_SHAPE(8x16), + .size = SPRITE_SIZE(8x16), + .priority = 1, +}; + +const struct CompressedSpriteSheet sSpriteSheet_TypeIcons2 = +{ + .data = gBattleIcons_Gfx2, + .size = (8*16) * 9, + .tag = TYPE_ICON_TAG_2, +}; + +const struct CompressedSpriteSheet sSpriteSheet_TypeIcons1 = +{ + .data = gBattleIcons_Gfx1, + .size = (8*16) * 10, + .tag = TYPE_ICON_TAG, +}; + +const struct SpriteTemplate sSpriteTemplate_TypeIcons1 = +{ + .tileTag = TYPE_ICON_TAG, + .paletteTag = TYPE_ICON_TAG, + .oam = &sOamData_TypeIcons, + .anims = sSpriteAnimTable_TypeIcons, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_TypeIcon +}; + +const struct SpriteTemplate sSpriteTemplate_TypeIcons2 = +{ + .tileTag = TYPE_ICON_TAG_2, + .paletteTag = TYPE_ICON_TAG_2, + .oam = &sOamData_TypeIcons, + .anims = sSpriteAnimTable_TypeIcons, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCB_TypeIcon +}; + +void LoadTypeIcons(u32 battler) +{ + u32 position; + + if (B_SHOW_TYPES == SHOW_TYPES_NEVER) + return; + + LoadTypeSpritesAndPalettes(); + + for (position = 0; position < gBattlersCount; ++position) + LoadTypeIconsPerBattler(battler, position); +} + +static void LoadTypeSpritesAndPalettes(void) +{ + if (IndexOfSpritePaletteTag(TYPE_ICON_TAG) != UCHAR_MAX) + return; + + LoadCompressedSpriteSheet(&sSpriteSheet_TypeIcons1); + LoadCompressedSpriteSheet(&sSpriteSheet_TypeIcons2); + LoadCompressedSpritePalette(&sTypeIconPal1); + LoadCompressedSpritePalette(&sTypeIconPal2); +} + +static void LoadTypeIconsPerBattler(u32 battler, u32 position) +{ + u32 typeNum, types[2]; + u32 battlerId = GetBattlerAtPosition(position); + bool32 useDoubleBattleCoords = UseDoubleBattleCoords(battlerId); + + if (!IsBattlerAlive(battlerId)) + return; + + for (typeNum = 0; typeNum < 2; ++typeNum) + types[typeNum] = GetMonPublicType(battlerId, typeNum); + + for (typeNum = 0; typeNum < 2; ++typeNum) + CreateSpriteFromType(position, useDoubleBattleCoords, types, typeNum, battler); +} + +static bool32 UseDoubleBattleCoords(u32 position) +{ + if (!IsDoubleBattle()) + return FALSE; + + if ((position == B_POSITION_PLAYER_LEFT) && (gBattleMons[B_POSITION_PLAYER_RIGHT].species == SPECIES_NONE)) + return FALSE; + + if ((position == B_POSITION_OPPONENT_LEFT) && (gBattleMons[B_POSITION_OPPONENT_RIGHT].species == SPECIES_NONE)) + return FALSE; + + return TRUE; +} + +static u32 GetMonPublicType(u32 battlerId, u32 typeNum) +{ + struct Pokemon* mon = GetBattlerData(battlerId); + u32 monSpecies = GetMonData(mon,MON_DATA_SPECIES,NULL); + struct Pokemon* monIllusion; + u32 illusionSpecies; + + if (ShouldHideUncaughtType(monSpecies)) + return TYPE_MYSTERY; + + monIllusion = GetIllusionMonPtr(battlerId); + illusionSpecies = GetMonData(monIllusion,MON_DATA_SPECIES,NULL); + + if (GetActiveGimmick(battlerId) == GIMMICK_TERA) + return GetMonDefensiveTeraType(mon,monIllusion,battlerId,typeNum,illusionSpecies,monSpecies); + + if (IsIllusionActiveAndTypeUnchanged(monIllusion,monSpecies, battlerId)) + return gSpeciesInfo[illusionSpecies].types[typeNum]; + + return gBattleMons[battlerId].types[typeNum]; +} + +static bool32 ShouldHideUncaughtType(u32 species) +{ + if (B_SHOW_TYPES != SHOW_TYPES_CAUGHT) + return FALSE; + + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species),FLAG_GET_CAUGHT)) + return FALSE; + + return TRUE; +} + +static u32 GetMonDefensiveTeraType(struct Pokemon * mon, struct Pokemon* monIllusion, u32 battlerId, u32 typeNum, u32 illusionSpecies, u32 monSpecies) +{ + u32 teraType = GetBattlerTeraType(battlerId); + u32 targetSpecies; + + if (teraType != TYPE_STELLAR) + return teraType; + + targetSpecies = (monIllusion != NULL) ? illusionSpecies : monSpecies; + + return gSpeciesInfo[targetSpecies].types[typeNum]; +} + +static u32 IsIllusionActiveAndTypeUnchanged(struct Pokemon* monIllusion, u32 monSpecies, u32 battlerId) +{ + u32 typeNum; + + if (monIllusion == NULL) + return FALSE; + + for (typeNum = 0; typeNum < 2; typeNum++) + if (gSpeciesInfo[monSpecies].types[typeNum] != gBattleMons[battlerId].types[typeNum]) + return FALSE; + + return TRUE; +} + +static void CreateSpriteFromType(u32 position, bool32 useDoubleBattleCoords, u32 types[], u32 typeNum, u32 battler) +{ + s32 x = 0, y = 0; + + if (ShouldSkipSecondType(types, typeNum)) + return; + + SetTypeIconXY(&x, &y, position, useDoubleBattleCoords, typeNum); + + CreateSpriteAndSetTypeSpriteAttributes(types[typeNum], x, y, position, battler, useDoubleBattleCoords); +} + +static bool32 ShouldSkipSecondType(u32 types[], u32 typeNum) +{ + if (!typeNum) + return FALSE; + + if (types[0] != types[1]) + return FALSE; + + return TRUE; +} + +static void SetTypeIconXY(s32* x, s32* y, u32 position, bool32 useDoubleBattleCoords, u32 typeNum) +{ + *x = sTypeIconPositions[position][useDoubleBattleCoords].x; + *y = sTypeIconPositions[position][useDoubleBattleCoords].y + (11 * typeNum); +} + +static void CreateSpriteAndSetTypeSpriteAttributes(u32 type, u32 x, u32 y, u32 position, u32 battler, bool32 useDoubleBattleCoords) +{ + struct Sprite* sprite; + const struct SpriteTemplate* spriteTemplate = gTypesInfo[type].useSecondTypeIconPalette ? &sSpriteTemplate_TypeIcons2 : &sSpriteTemplate_TypeIcons1; + u32 spriteId = CreateSpriteAtEnd(spriteTemplate, x, y, UCHAR_MAX); + + if (spriteId == MAX_SPRITES) + return; + + sprite = &gSprites[spriteId]; + sprite->tMonPosition = position; + sprite->tBattlerId = battler; + sprite->tVerticalPosition = y; + + sprite->hFlip = ShouldFlipTypeIcon(useDoubleBattleCoords, position, type); + + StartSpriteAnim(sprite, type); +} + +static bool32 ShouldFlipTypeIcon(bool32 useDoubleBattleCoords, u32 position, u32 typeId) +{ + bool32 side = (useDoubleBattleCoords) ? B_SIDE_OPPONENT : B_SIDE_PLAYER; + + if (GetBattlerSide(GetBattlerAtPosition(position)) != side) + return FALSE; + + return !gTypesInfo[typeId].isSpecialCaseType; +} + +static void SpriteCB_TypeIcon(struct Sprite* sprite) +{ + u32 position = sprite->tMonPosition; + u32 battlerId = sprite->tBattlerId; + bool32 useDoubleBattleCoords = UseDoubleBattleCoords(GetBattlerAtPosition(position)); + + if (sprite->tHideIconTimer == NUM_FRAMES_HIDE_TYPE_ICON) + { + DestroyTypeIcon(sprite); + return; + } + + if (ShouldHideTypeIcon(battlerId)) + { + sprite->x += GetTypeIconHideMovement(useDoubleBattleCoords, position); + ++sprite->tHideIconTimer; + return; + } + + sprite->x += GetTypeIconSlideMovement(useDoubleBattleCoords,position, sprite->x); + sprite->y = GetTypeIconBounceMovement(sprite->tVerticalPosition,position); +} + +static void DestroyTypeIcon(struct Sprite* sprite) +{ + u32 i; + DestroySpriteAndFreeResources(sprite); + + for (i = 0; i < MAX_SPRITES; ++i) + { + if (!gSprites[i].inUse) + continue; + + if (gSprites[i].template->paletteTag == TYPE_ICON_TAG) + return; + } + + FreeSpritePaletteByTag(TYPE_ICON_TAG); + FreeSpritePaletteByTag(TYPE_ICON_TAG_2); +} + +static bool32 ShouldHideTypeIcon(u32 battlerId) +{ + return gBattlerControllerFuncs[battlerId] != PlayerHandleChooseMove + && gBattlerControllerFuncs[battlerId] != HandleInputChooseMove + && gBattlerControllerFuncs[battlerId] != HandleChooseMoveAfterDma3 + && gBattlerControllerFuncs[battlerId] != HandleInputChooseMove + && gBattlerControllerFuncs[battlerId] != HandleInputChooseTarget + && gBattlerControllerFuncs[battlerId] != HandleMoveSwitching + && gBattlerControllerFuncs[battlerId] != HandleInputChooseMove; +} + +static s32 GetTypeIconHideMovement(bool32 useDoubleBattleCoords, u32 position) +{ + if (useDoubleBattleCoords) + { + if (position == B_POSITION_PLAYER_LEFT || position == B_POSITION_PLAYER_RIGHT) + return 1; + else + return -1; + } + + if (position == B_POSITION_PLAYER_LEFT) + return -1; + else + return 1; +} + +static s32 GetTypeIconSlideMovement(bool32 useDoubleBattleCoords, u32 position, s32 xPos) +{ + if (useDoubleBattleCoords) + { + switch (position) + { + case B_POSITION_PLAYER_LEFT: + case B_POSITION_PLAYER_RIGHT: + if (xPos > sTypeIconPositions[position][useDoubleBattleCoords].x - 10) + return -1; + break; + default: + case B_POSITION_OPPONENT_LEFT: + case B_POSITION_OPPONENT_RIGHT: + if (xPos < sTypeIconPositions[position][useDoubleBattleCoords].x + 10) + return 1; + break; + } + return 0; + } + + if (position == B_POSITION_PLAYER_LEFT) + { + if (xPos < sTypeIconPositions[position][useDoubleBattleCoords].x + 10) + return 1; + } + else + { + if (xPos > sTypeIconPositions[position][useDoubleBattleCoords].x - 10) + return -1; + } + return 0; +} + +static s32 GetTypeIconBounceMovement(s32 originalY, u32 position) +{ + struct Sprite* healthbox = &gSprites[gHealthboxSpriteIds[GetBattlerAtPosition(position)]]; + return originalY + healthbox->y2; +} +