update player controller

This commit is contained in:
cawtds
2025-01-06 23:08:33 +01:00
parent 2d21579cd7
commit a027c98cd9
62 changed files with 1508 additions and 272 deletions

View File

@@ -45,6 +45,7 @@ SUPER_ER = 2C
LV = 34
'=' = 35
';' = 36
V_D_ARROW = 38
'¿' = 51
'¡' = 52
PK = 53

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

BIN
graphics/types/bug.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

BIN
graphics/types/dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

BIN
graphics/types/dragon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

BIN
graphics/types/electric.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

BIN
graphics/types/fairy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

BIN
graphics/types/fight.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

BIN
graphics/types/fire.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

BIN
graphics/types/flying.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

BIN
graphics/types/ghost.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

BIN
graphics/types/grass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

BIN
graphics/types/ground.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

BIN
graphics/types/ice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

View File

@@ -0,0 +1,19 @@
JASC-PAL
0100
16
0 0 0
255 213 49
246 131 49
197 49 41
230 197 106
189 164 57
139 106 49
255 255 123
172 172 123
222 222 197
115 90 74
74 65 57
189 189 213
0 0 0
131 123 115
255 255 255

View File

@@ -0,0 +1,19 @@
JASC-PAL
0100
16
0 0 0
205 197 255
172 148 246
115 90 156
106 148 246
156 222 222
213 255 238
74 57 82
255 90 139
255 197 180
148 98 98
164 65 164
222 131 189
148 148 164
131 123 115
255 255 255

View File

@@ -0,0 +1,19 @@
JASC-PAL
0100
16
0 0 0
197 255 98
123 205 82
90 131 65
115 57 255
74 57 148
189 164 255
172 189 32
222 230 49
123 148 16
106 164 148
115 205 180
32 106 98
0 0 0
131 123 115
255 255 255

BIN
graphics/types/mystery.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

BIN
graphics/types/none.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

BIN
graphics/types/normal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

BIN
graphics/types/poison.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

BIN
graphics/types/psychic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

BIN
graphics/types/rock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

BIN
graphics/types/steel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

BIN
graphics/types/stellar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
graphics/types/water.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@@ -158,7 +158,7 @@ enum
CONTROLLER_PRINTSTRING,
CONTROLLER_PRINTSTRINGPLAYERONLY,
CONTROLLER_CHOOSEACTION,
CONTROLLER_UNKNOWNYESNOBOX,
CONTROLLER_YESNOBOX,
CONTROLLER_CHOOSEMOVE,
CONTROLLER_OPENBAG,
CONTROLLER_CHOOSEPOKEMON,
@@ -307,17 +307,23 @@ void SetBattleEndCallbacks(u32 battler);
void SetControllerToPlayer(u32 battler);
void PlayerHandleBallThrowAnim(u32 battler);
void SpriteCB_FreePlayerSpriteLoadMonSpriteOld(struct Sprite *sprite);
void SetCB2ToReshowScreenAfterMenu(void);
void SetCB2ToReshowScreenAfterMenu2(void);
void CB2_SetUpReshowBattleScreenAfterMenu(void);
void CB2_SetUpReshowBattleScreenAfterMenu2(void);
void Task_PlayerController_RestoreBgmAfterCry(u8 taskId);
void ActionSelectionCreateCursorAt(u8 cursorPos, u8 unused);
void ActionSelectionDestroyCursorAt(u8 cursorPos);
void InitMoveSelectionsVarsAndStrings(u32 battler);
void MoveSelectionCreateCursorAt(u8 cursorPos, u8 arg1);
void MoveSelectionDestroyCursorAt(u8 cursorPos);
void HandleInputChooseMove(u32 battler);
u32 LinkPlayerGetTrainerPicId(u32 multiplayerId);
void PlayerHandleExpUpdate(u32 battler);
void PlayerHandleChooseMove(u32 battler);
void HandleInputChooseMove(u32 battler);
void HandleInputChooseTarget(u32 battler);
void HandleInputShowEntireFieldTargets(u32 battler);
void HandleInputShowTargets(u32 battler);
void HandleMoveSwitching(u32 battler);
void HandleChooseMoveAfterDma3(u32 battler);
// recorded player controller
void SetControllerToRecordedPlayer(u32 battler);

View File

@@ -96,6 +96,7 @@ s8 GetChosenMovePriority(u32 battlerId);
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect);
u32 GetBattlerTotalSpeedStat(u32 battler);
void SpecialStatusesClear(void);
u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost);
s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2,
u32 holdEffectBattler1, u32 holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2);
s32 GetWhichBattlerFasterOrTies(u32 battler1, u32 battler2, bool32 ignoreChosenMoves);

View File

@@ -6523,4 +6523,9 @@ extern const u32 gBattleAnimBgImage_Swamp[];
extern const u32 gBattleAnimBGPalette_Swamp[];
extern const u32 gBattleAnimBgTilemap_Swamp[];
extern const u32 gBattleIcons_Gfx1[];
extern const u32 gBattleIcons_Gfx2[];
extern const u32 gBattleIcons_Pal1[];
extern const u32 gBattleIcons_Pal2[];
#endif //GUARD_GRAPHICS_H

View File

@@ -18,7 +18,9 @@ struct Item
u8 pluralName[ITEM_NAME_PLURAL_LENGTH];
u8 holdEffect;
u8 holdEffectParam;
u8 importance;
u8 importance:2;
u8 notConsumed:1;
u8 padding:5;
u8 pocket;
u8 type;
u8 battleUsage;
@@ -57,6 +59,7 @@ u8 ItemId_GetHoldEffectParam(u16 itemId);
const u8 *ItemId_GetDescription(u16 itemId);
bool32 ItemId_CopyDescription(u8 *a, u32 itemId, u32 c);
u8 ItemId_GetImportance(u16 itemId);
u8 ItemId_GetConsumability(u16 itemId);
u8 ItemId_GetUnknownValue(u16 itemId);
u8 ItemId_GetPocket(u16 itemId);
u8 ItemId_GetType(u16 itemId);

View File

@@ -24,7 +24,7 @@ extern struct BagStruct gBagMenuState;
extern u16 gSpecialVar_ItemId;
// Exported ROM declarations
void CB2_SetUpReshowBattleScreenAfterMenu(void);
void SetBagOpenFalse(void);
void ResetBagCursorPositions(void);
void InitPokedudeBag(u8);
void CB2_BagMenuFromStartMenu(void);

33
include/line_break.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef GUARD_LINE_BREAK_H
#define GUARD_LINE_BREAK_H
#define BADNESS_UNFILLED 1 // Badness added per pixel diff from max width
#define BADNESS_JAGGED 1 // Badness added per pixel diff from longest, squared per line
#define BADNESS_RUNT 100 // Badness added if there's a runt
#define BADNESS_OVERFLOW 100 // Badness added per pixel overflow, squared per line (not used)
#define BADNESS_WIDE_SPACE 1 // Badness added per extra pixel width (not used)
#define MAX_SPACE_WIDTH 5
struct StringWord {
u32 startIndex:16;
u32 length:8;
u32 width:8;
};
struct StringLine {
struct StringWord *words;
u16 numWords;
u8 spaceWidth;
u8 extraSpaceWidth;
};
void StripLineBreaks(u8 *src);
void BreakStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId);
void BreakSubStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId);
bool32 IsWordSplittingChar(const u8 *src, u32 index);
u32 GetStringBadness(struct StringLine *stringLines, u32 numLines, u32 maxWidth);
void BuildNewString(struct StringLine *stringLines, u32 numLines, u32 maxLines, u8 *str);
bool32 StringHasManualBreaks(u8 *src);
#endif // GUARD_LINE_BREAK_H

View File

@@ -78,7 +78,7 @@ void ClearSelectedPartyOrder(void);
void ChooseMonForTradingBoard(u8 menuType, MainCallback callback);
void ChooseMonForMoveTutor(void);
void ChooseMonForWirelessMinigame(void);
void OpenPartyMenuInTutorialBattle(u8 partyAction);
void OpenPartyMenuInBattle(u8 partyAction);
void Pokedude_OpenPartyMenuInBattle(void);
void Pokedude_ChooseMonForInBattleItem(void);
void EnterPartyFromItemMenuInBattle(void);

View File

@@ -782,5 +782,6 @@ u16 HoennNumToSpecies(u16 hoennNum);
u8 CopyMonToPC(struct Pokemon *mon);
void UpdateDaysPassedSinceFormChange(u16 days);
void TrySetDayLimitToFormChange(struct Pokemon *mon);
u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler);
#endif // GUARD_POKEMON_H

18
include/type_icons.h Normal file
View File

@@ -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

View File

@@ -52,7 +52,7 @@ static void (*const sLinkOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(u32 batt
[CONTROLLER_PRINTSTRING] = BtlController_HandlePrintString, // done
[CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty, // done
[CONTROLLER_CHOOSEACTION] = BtlController_Empty, // done
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty, // done
[CONTROLLER_YESNOBOX] = BtlController_Empty, // done
[CONTROLLER_CHOOSEMOVE] = BtlController_Empty, // done
[CONTROLLER_OPENBAG] = BtlController_Empty, // done
[CONTROLLER_CHOOSEPOKEMON] = BtlController_Empty, // done

View File

@@ -49,7 +49,7 @@ static void (*const sLinkPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battl
[CONTROLLER_PRINTSTRING] = BtlController_HandlePrintString, // done
[CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty, // done
[CONTROLLER_CHOOSEACTION] = BtlController_Empty, // done
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty, // done
[CONTROLLER_YESNOBOX] = BtlController_Empty, // done
[CONTROLLER_CHOOSEMOVE] = BtlController_Empty, // done
[CONTROLLER_OPENBAG] = BtlController_Empty, // done
[CONTROLLER_CHOOSEPOKEMON] = BtlController_Empty, // done

View File

@@ -70,7 +70,7 @@ static void (*const sOakOldManBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler
[CONTROLLER_PRINTSTRING] = OakOldManHandlePrintString, // done
[CONTROLLER_PRINTSTRINGPLAYERONLY] = OakOldManHandlePrintSelectionString, // done
[CONTROLLER_CHOOSEACTION] = OakOldManHandleChooseAction, // done
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty, // done
[CONTROLLER_YESNOBOX] = BtlController_Empty, // done
[CONTROLLER_CHOOSEMOVE] = OakOldManHandleChooseMove, // done
[CONTROLLER_OPENBAG] = OakOldManHandleChooseItem, // done
[CONTROLLER_CHOOSEPOKEMON] = OakOldManHandleChoosePokemon, // done
@@ -291,7 +291,7 @@ static void OpenPartyMenuToChooseMon(u32 battler)
caseId = gTasks[gBattleControllerData[battler]].data[0];
DestroyTask(gBattleControllerData[battler]);
FreeAllWindowBuffers();
OpenPartyMenuInTutorialBattle(caseId);
OpenPartyMenuInBattle(caseId);
}
}

View File

@@ -68,7 +68,7 @@ static void (*const sOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler)
[CONTROLLER_PRINTSTRING] = BtlController_HandlePrintString, // done
[CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty, // done
[CONTROLLER_CHOOSEACTION] = OpponentHandleChooseAction, // done
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty, // done
[CONTROLLER_YESNOBOX] = BtlController_Empty, // done
[CONTROLLER_CHOOSEMOVE] = OpponentHandleChooseMove, // done
[CONTROLLER_OPENBAG] = OpponentHandleChooseItem, // done
[CONTROLLER_CHOOSEPOKEMON] = OpponentHandleChoosePokemon, // done

File diff suppressed because it is too large Load Diff

View File

@@ -70,7 +70,7 @@ static void (*const sPlayerPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 bat
[CONTROLLER_PRINTSTRING] = BtlController_HandlePrintString,
[CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty,
[CONTROLLER_CHOOSEACTION] = PlayerPartnerHandleChooseAction,
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty,
[CONTROLLER_YESNOBOX] = BtlController_Empty,
[CONTROLLER_CHOOSEMOVE] = PlayerPartnerHandleChooseMove,
[CONTROLLER_OPENBAG] = BtlController_Empty,
[CONTROLLER_CHOOSEPOKEMON] = PlayerPartnerHandleChoosePokemon,

View File

@@ -95,7 +95,7 @@ static void (*const sPokedudeBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler)
[CONTROLLER_PRINTSTRING] = BtlController_HandlePrintString, // done
[CONTROLLER_PRINTSTRINGPLAYERONLY] = PokedudeHandlePrintSelectionString, // done
[CONTROLLER_CHOOSEACTION] = PokedudeHandleChooseAction, // done
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty, // done
[CONTROLLER_YESNOBOX] = BtlController_Empty, // done
[CONTROLLER_CHOOSEMOVE] = PokedudeHandleChooseMove, // done
[CONTROLLER_OPENBAG] = PokedudeHandleChooseItem, // done
[CONTROLLER_CHOOSEPOKEMON] = PokedudeHandleChoosePokemon, // done

View File

@@ -74,7 +74,7 @@ static void (*const sRecordedOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(u32
[CONTROLLER_PRINTSTRING] = RecordedOpponentHandlePrintString,
[CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty,
[CONTROLLER_CHOOSEACTION] = RecordedOpponentHandleChooseAction,
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty,
[CONTROLLER_YESNOBOX] = BtlController_Empty,
[CONTROLLER_CHOOSEMOVE] = RecordedOpponentHandleChooseMove,
[CONTROLLER_OPENBAG] = RecordedOpponentHandleChooseItem,
[CONTROLLER_CHOOSEPOKEMON] = RecordedOpponentHandleChoosePokemon,

View File

@@ -72,7 +72,7 @@ static void (*const sRecordedPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 ba
[CONTROLLER_PRINTSTRING] = RecordedPlayerHandlePrintString,
[CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty,
[CONTROLLER_CHOOSEACTION] = RecordedPlayerHandleChooseAction,
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty,
[CONTROLLER_YESNOBOX] = BtlController_Empty,
[CONTROLLER_CHOOSEMOVE] = RecordedPlayerHandleChooseMove,
[CONTROLLER_OPENBAG] = RecordedPlayerHandleChooseItem,
[CONTROLLER_CHOOSEPOKEMON] = RecordedPlayerHandleChoosePokemon,

View File

@@ -52,7 +52,7 @@ static void (*const sSafariBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) =
[CONTROLLER_PRINTSTRING] = BtlController_HandlePrintString, // done
[CONTROLLER_PRINTSTRINGPLAYERONLY] = SafariHandlePrintSelectionString, // done
[CONTROLLER_CHOOSEACTION] = SafariHandleChooseAction, // done
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty, // done
[CONTROLLER_YESNOBOX] = BtlController_Empty, // done
[CONTROLLER_CHOOSEMOVE] = BtlController_Empty, // done
[CONTROLLER_OPENBAG] = SafariHandleChooseItem, // done
[CONTROLLER_CHOOSEPOKEMON] = BtlController_Empty, // done

View File

@@ -2052,6 +2052,7 @@ const struct Item gItemsInfo[] =
"A glass flute that "
"awakens\nsleeping "
"Pokémon."),
.notConsumed = TRUE,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Medicine,
@@ -2070,6 +2071,7 @@ const struct Item gItemsInfo[] =
"A glass flute that "
"snaps Pokémon\n"
"out of confusion."),
.notConsumed = TRUE,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@@ -2088,6 +2090,7 @@ const struct Item gItemsInfo[] =
"A glass flute that "
"snaps Pokémon\n"
"out of attraction."),
.notConsumed = TRUE,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse,
@@ -2109,6 +2112,7 @@ const struct Item gItemsInfo[] =
"A glass flute that "
"keeps away\nwild "
"Pokémon."),
.notConsumed = TRUE,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_BlackWhiteFlute,
@@ -2125,6 +2129,7 @@ const struct Item gItemsInfo[] =
.description = COMPOUND_STRING(
"A glass flute that "
"lures wild\nPokémon."),
.notConsumed = TRUE,
.pocket = POCKET_ITEMS,
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_BlackWhiteFlute,

View File

@@ -1937,3 +1937,8 @@ const u32 gBattleAnimBgPalette_ZMoveMountain[] = INCBIN_U32("graphics/battle_ani
const u32 gBattleAnimBgTilemap_ZMoveMountain[] = INCBIN_U32("graphics/battle_anims/backgrounds/zmove_mountain.bin.lz");
const u32 gBattleAnimBgPalette_SteelBeam[] = INCBIN_U32("graphics/battle_anims/backgrounds/steel_beam.gbapal.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");

View File

@@ -662,6 +662,11 @@ u8 ItemId_GetImportance(u16 itemId)
return gItemsInfo[SanitizeItemId(itemId)].importance;
}
u8 ItemId_GetConsumability(u16 itemId)
{
return !gItemsInfo[SanitizeItemId(itemId)].notConsumed;
}
u8 ItemId_GetPocket(u16 itemId)
{
return gItemsInfo[SanitizeItemId(itemId)].pocket;

View File

@@ -351,7 +351,7 @@ void CB2_BagMenuFromStartMenu(void)
void CB2_BagMenuFromBattle(void)
{
GoToBagMenu(ITEMMENULOCATION_BATTLE, OPEN_BAG_LAST, SetCB2ToReshowScreenAfterMenu2);
GoToBagMenu(ITEMMENULOCATION_BATTLE, OPEN_BAG_LAST, CB2_SetUpReshowBattleScreenAfterMenu2);
}
static void CB2_BagMenuRun(void)
@@ -949,7 +949,7 @@ void Bag_BeginCloseWin0Animation(void)
gBagMenuState.bagOpen = FALSE;
}
void CB2_SetUpReshowBattleScreenAfterMenu(void)
void SetBagOpenFalse(void)
{
gBagMenuState.bagOpen = FALSE;
}
@@ -2101,7 +2101,7 @@ void InitOldManBag(void)
BackUpPlayerBag();
AddBagItem(ITEM_POTION, 1);
AddBagItem(ITEM_POKE_BALL, 1);
GoToBagMenu(ITEMMENULOCATION_OLD_MAN, OPEN_BAG_ITEMS, SetCB2ToReshowScreenAfterMenu2);
GoToBagMenu(ITEMMENULOCATION_OLD_MAN, OPEN_BAG_ITEMS, CB2_SetUpReshowBattleScreenAfterMenu2);
}
#define tFrameCounter data[8]
@@ -2183,11 +2183,11 @@ void InitPokedudeBag(u8 a0)
location = a0;
break;
case ITEMMENULOCATION_TTVSCR_STATUS:
cb2 = SetCB2ToReshowScreenAfterMenu2;
cb2 = CB2_SetUpReshowBattleScreenAfterMenu2;
location = ITEMMENULOCATION_TTVSCR_STATUS;
break;
case ITEMMENULOCATION_TTVSCR_CATCHING:
cb2 = SetCB2ToReshowScreenAfterMenu2;
cb2 = CB2_SetUpReshowBattleScreenAfterMenu2;
location = ITEMMENULOCATION_TTVSCR_CATCHING;
break;
}

281
src/line_break.c Normal file
View File

@@ -0,0 +1,281 @@
#include "global.h"
#include "line_break.h"
#include "text.h"
#include "malloc.h"
void StripLineBreaks(u8 *src)
{
u32 currIndex = 0;
while (src[currIndex] != EOS)
{
if (src[currIndex] == CHAR_PROMPT_SCROLL || src[currIndex] == CHAR_NEWLINE)
src[currIndex] = CHAR_SPACE;
currIndex++;
}
}
void BreakStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId)
{
u32 currIndex = 0;
u8 *currSrc = src;
while (src[currIndex] != EOS)
{
if (src[currIndex] == CHAR_PROMPT_CLEAR)
{
u8 replacedChar = src[currIndex + 1];
src[currIndex + 1] = EOS;
BreakSubStringAutomatic(currSrc, maxWidth, screenLines, fontId);
src[currIndex + 1] = replacedChar;
currSrc = &src[currIndex + 1];
}
currIndex++;
}
BreakSubStringAutomatic(currSrc, maxWidth, screenLines, fontId);
}
void BreakSubStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId)
{
// If the string already has line breaks, don't interfere with them
if (StringHasManualBreaks(src))
return;
// Sanity check
if (src[0] == EOS)
return;
u32 numChars = 1;
u32 numWords = 1;
u32 currWordIndex = 0;
u32 currWordLength = 1;
bool32 isPrevCharSplitting = FALSE;
bool32 isCurrCharSplitting;
// Get numbers of chars in string and count words
while (src[numChars] != EOS)
{
isCurrCharSplitting = IsWordSplittingChar(src, numChars);
if (isCurrCharSplitting && !isPrevCharSplitting)
numWords++;
isPrevCharSplitting = isCurrCharSplitting;
numChars++;
}
// Allocate enough space for word data
struct StringWord *allWords = Alloc(numWords*sizeof(struct StringWord));
allWords[currWordIndex].startIndex = 0;
allWords[currWordIndex].width = 0;
isPrevCharSplitting = FALSE;
// Fill in word begin index and lengths
for (u32 i = 1; i < numChars; i++)
{
isCurrCharSplitting = IsWordSplittingChar(src, i);
if (isCurrCharSplitting && !isPrevCharSplitting)
{
allWords[currWordIndex].length = currWordLength;
currWordIndex++;
currWordLength = 0;
}
else if (!isCurrCharSplitting && isPrevCharSplitting)
{
allWords[currWordIndex].startIndex = i;
allWords[currWordIndex].width = 0;
currWordLength++;
}
else
{
currWordLength++;
}
isPrevCharSplitting = isCurrCharSplitting;
}
allWords[currWordIndex].length = currWordLength;
// Fill in individual word widths
for (u32 i = 0; i < numWords; i++)
{
for (u32 j = 0; j < allWords[i].length; j++)
allWords[i].width += GetGlyphWidth(src[allWords[i].startIndex + j], FALSE, fontId);
}
// Step 1: Does it all fit one one line? Then no break
// Step 2: Try to split across minimum number of lines
u32 spaceWidth = GetGlyphWidth(0, FALSE, fontId);
u32 totalWidth = allWords[0].width;
// Calculate total widths without any line breaks
for (u32 i = 1; i < numWords; i++)
totalWidth += allWords[i].width + spaceWidth;
// If it doesn't fit on 1 line, do fancy line break calculation
// NOTE: Currently the line break calculation isn't fancy
if (totalWidth > maxWidth)
{
// Figure out how many lines are needed with naive method
u32 currLineWidth = 0;
u32 totalLines = 1;
bool32 shouldTryAgain;
for (currWordIndex = 0; currWordIndex < numWords; currWordIndex++)
{
if (currLineWidth + allWords[currWordIndex].length > maxWidth)
{
totalLines++;
currLineWidth = allWords[currWordIndex].width;
}
else
{
currLineWidth += allWords[currWordIndex].width + spaceWidth;
}
}
// LINE LAYOUT STARTS HERE
struct StringLine *stringLines;
do
{
shouldTryAgain = FALSE;
u16 targetLineWidth = totalWidth/totalLines;
stringLines = Alloc(totalLines*sizeof(struct StringLine));
for (u32 lineIndex = 0; lineIndex < totalLines; lineIndex++)
{
stringLines[lineIndex].numWords = 0;
stringLines[lineIndex].spaceWidth = spaceWidth;
stringLines[lineIndex].extraSpaceWidth = 0;
}
currWordIndex = 0;
u16 currLineIndex = 0;
stringLines[currLineIndex].words = &allWords[currWordIndex];
stringLines[currLineIndex].numWords = 1;
currLineWidth = allWords[currWordIndex].width;
currWordIndex++;
while (currWordIndex < numWords)
{
if (currLineWidth + spaceWidth + allWords[currWordIndex].width > maxWidth)
{
// go to next line
currLineIndex++;
if (currLineIndex == totalLines)
{
totalLines++;
Free(stringLines);
shouldTryAgain = TRUE;
break;
}
stringLines[currLineIndex].words = &allWords[currWordIndex];
stringLines[currLineIndex].numWords = 1;
currLineWidth = allWords[currWordIndex].width;
currWordIndex++;
}
else if (currLineWidth > targetLineWidth)
{
// go to next line
currLineIndex++;
if (currLineIndex == totalLines)
{
totalLines++;
Free(stringLines);
shouldTryAgain = TRUE;
break;
}
stringLines[currLineIndex].words = &allWords[currWordIndex];
stringLines[currLineIndex].numWords = 1;
currLineWidth = allWords[currWordIndex].width;
currWordIndex++;
}
else
{
// continue on current line
// add word and space width
currLineWidth += spaceWidth + allWords[currWordIndex].width;
stringLines[currLineIndex].numWords++;
currWordIndex++;
}
}
} while (shouldTryAgain);
//u32 currBadness = GetStringBadness(stringLines, totalLines, maxWidth);
BuildNewString(stringLines, totalLines, screenLines, src);
Free(stringLines);
}
Free(allWords);
}
// Only allow word splitting on allowed chars
bool32 IsWordSplittingChar(const u8 *src, u32 index)
{
switch (src[index])
{
case CHAR_SPACE:
return TRUE;
default:
return FALSE;
}
}
// Badness calculation
// unfilled lines scale linerarly
// jagged lines scales by the square
// runts scale linearly
// numbers not final
// ISN'T ACTUALLY USED RIGHT NOW
u32 GetStringBadness(struct StringLine *stringLines, u32 numLines, u32 maxWidth)
{
u32 badness = 0;
u32 *lineWidths = Alloc(numLines*4);
u32 widestWidth = 0;
for (u32 i = 0; i < numLines; i++)
{
lineWidths[i] = 0;
for (u32 j = 0; j < stringLines[i].numWords; j++)
lineWidths[i] += stringLines[i].words[j].width;
lineWidths[i] += (stringLines[i].numWords-1)*stringLines[i].spaceWidth;
if (lineWidths[i] > widestWidth)
widestWidth = lineWidths[i];
if (stringLines[i].numWords == 1)
badness += BADNESS_RUNT;
}
for (u32 i = 0; i < numLines; i++)
{
u32 extraSpaceWidth = 0;
if (lineWidths[i] != widestWidth)
{
// Not the best way to do this, ideally a line should be allowed to get longer than current widest
// line. But then the widest line has to be recalculated.
while (lineWidths[i] + (extraSpaceWidth + 1) * (stringLines[i].numWords - 1) < widestWidth && extraSpaceWidth < MAX_SPACE_WIDTH)
extraSpaceWidth++;
lineWidths[i] += extraSpaceWidth*(stringLines[i].numWords-1);
}
badness += (maxWidth - lineWidths[i]) * BADNESS_UNFILLED;
u32 baseBadness = (widestWidth - lineWidths[i]) * BADNESS_JAGGED;
badness += baseBadness*baseBadness;
stringLines[i].extraSpaceWidth = extraSpaceWidth;
}
Free(lineWidths);
return badness;
}
// Build the new string from the data stored in the StringLine structs
void BuildNewString(struct StringLine *stringLines, u32 numLines, u32 maxLines, u8 *str)
{
u32 srcCharIndex = 0;
for (u32 lineIndex = 0; lineIndex < numLines; lineIndex++)
{
srcCharIndex += stringLines[lineIndex].words[0].length;
for (u32 wordIndex = 1; wordIndex < stringLines[lineIndex].numWords; wordIndex++)
// Add length of word and a space
srcCharIndex += stringLines[lineIndex].words[wordIndex].length + 1;
if (lineIndex + 1 < numLines)
{
// Add the appropriate line break depending on line number
if (lineIndex >= maxLines - 1 && numLines > maxLines)
str[srcCharIndex] = CHAR_PROMPT_SCROLL;
else
str[srcCharIndex] = CHAR_NEWLINE;
srcCharIndex++;
}
}
}
bool32 StringHasManualBreaks(u8 *src)
{
u32 charIndex = 0;
while (src[charIndex] != EOS)
{
if (src[charIndex] == CHAR_PROMPT_SCROLL || src[charIndex] == CHAR_NEWLINE)
return TRUE;
charIndex++;
}
return FALSE;
}

View File

@@ -6562,7 +6562,7 @@ static u8 GetPartyLayoutFromBattleType(void)
return PARTY_LAYOUT_DOUBLE;
}
void OpenPartyMenuInTutorialBattle(u8 partyAction)
void OpenPartyMenuInBattle(u8 partyAction)
{
if (!BtlCtrl_OakOldMan_TestState2Flag(FIRST_BATTLE_MSG_FLAG_PARTY_MENU) && (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE))
{
@@ -6572,7 +6572,7 @@ void OpenPartyMenuInTutorialBattle(u8 partyAction)
FALSE,
PARTY_MSG_NONE,
Task_FirstBattleEnterParty_WaitFadeIn,
SetCB2ToReshowScreenAfterMenu);
CB2_SetUpReshowBattleScreenAfterMenu);
BtlCtrl_OakOldMan_SetState2Flag(FIRST_BATTLE_MSG_FLAG_PARTY_MENU);
}
else
@@ -6583,7 +6583,7 @@ void OpenPartyMenuInTutorialBattle(u8 partyAction)
FALSE,
PARTY_MSG_CHOOSE_MON,
Task_HandleChooseMonInput,
SetCB2ToReshowScreenAfterMenu);
CB2_SetUpReshowBattleScreenAfterMenu);
}
ReshowBattleScreenDummy();
UpdatePartyToBattleOrder();
@@ -6591,7 +6591,7 @@ void OpenPartyMenuInTutorialBattle(u8 partyAction)
void Pokedude_OpenPartyMenuInBattle(void)
{
InitPartyMenu(PARTY_MENU_TYPE_IN_BATTLE, GetPartyLayoutFromBattleType(), PARTY_ACTION_CHOOSE_MON, FALSE, PARTY_MSG_CHOOSE_MON, Task_PartyMenu_Pokedude, SetCB2ToReshowScreenAfterMenu);
InitPartyMenu(PARTY_MENU_TYPE_IN_BATTLE, GetPartyLayoutFromBattleType(), PARTY_ACTION_CHOOSE_MON, FALSE, PARTY_MSG_CHOOSE_MON, Task_PartyMenu_Pokedude, CB2_SetUpReshowBattleScreenAfterMenu);
ReshowBattleScreenDummy();
UpdatePartyToBattleOrder();
}
@@ -6948,8 +6948,8 @@ static void UpdatePartyToFieldOrder(void)
static void CB2_SetUpExitToBattleScreen(void)
{
CB2_SetUpReshowBattleScreenAfterMenu();
SetMainCallback2(SetCB2ToReshowScreenAfterMenu);
SetBagOpenFalse();
SetMainCallback2(CB2_SetUpReshowBattleScreenAfterMenu);
}
void ShowPartyMenuToShowcaseMultiBattleParty(void)

View File

@@ -6561,3 +6561,11 @@ void UpdateDaysPassedSinceFormChange(u16 days)
}
}
}
u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler)
{
u32 moveType = GetDynamicMoveType(mon, move, battler, NULL);
if (moveType != TYPE_NONE)
return moveType;
return GetMoveType(move);
}

View File

@@ -1466,7 +1466,7 @@ static void Task_Pokedude_Run(u8 taskId)
sTMCaseStaticResources.scrollOffset = sPokedudeBagBackup->scrollOffset;
Free(sPokedudeBagBackup);
CpuFastCopy(gPlttBufferFaded, gPlttBufferUnfaded, PLTT_SIZE);
CB2_SetUpReshowBattleScreenAfterMenu();
SetBagOpenFalse();
BeginNormalPaletteFade(PALETTES_ALL, -2, 0, 16, 0);
tPokedudeState++;
}

552
src/type_icons.c Normal file
View File

@@ -0,0 +1,552 @@
#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 void FreeAllTypeIconResources(void);
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 = GetPartyBattlerData(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(SpeciesToNationalDexNum(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 const u32 typeIconTags[] =
{
TYPE_ICON_TAG,
TYPE_ICON_TAG_2
};
static void DestroyTypeIcon(struct Sprite* sprite)
{
u32 spriteId, tag;
DestroySpriteAndFreeResources(sprite);
for (spriteId = 0; spriteId < MAX_SPRITES; ++spriteId)
{
if (!gSprites[spriteId].inUse)
continue;
for (tag = 0; tag < 2; tag++)
{
if (gSprites[spriteId].template->paletteTag == typeIconTags[tag])
return;
if (gSprites[spriteId].template->tileTag == typeIconTags[tag])
return;
}
}
FreeAllTypeIconResources();
}
static void FreeAllTypeIconResources(void)
{
u32 tag;
for (tag = 0; tag < 2; tag++)
{
FreeSpriteTilesByTag(typeIconTags[tag]);
FreeSpritePaletteByTag(typeIconTags[tag]);
}
}
static void (* const sShowTypesControllerFuncs[])(u32 battler) =
{
PlayerHandleChooseMove,
HandleChooseMoveAfterDma3,
HandleInputChooseTarget,
HandleInputShowTargets,
HandleInputShowEntireFieldTargets,
HandleMoveSwitching,
HandleInputChooseMove,
};
static bool32 ShouldHideTypeIcon(u32 battlerId)
{
u32 funcIndex;
for (funcIndex = 0; funcIndex < ARRAY_COUNT(sShowTypesControllerFuncs); funcIndex++)
if (gBattlerControllerFuncs[battlerId] == sShowTypesControllerFuncs[funcIndex])
return FALSE;
return TRUE;
}
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;
}