summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPikalaxALT <pikalaxalt@gmail.com>2018-05-10 09:47:12 -0400
committerPikalaxALT <pikalaxalt@gmail.com>2018-05-10 09:47:12 -0400
commitdfc83cf28f0040a62ea52fb7ab7783d4e15baded (patch)
treead39d622d237df4d97ee6c8c0ba0346aa1a59fd3 /src
parent5efe8f3a0d0db0228fd0980c90013a4602c731b3 (diff)
parent7defc27b994069715e5749245700d20dd740e4f0 (diff)
Merge branch 'master' into contest
Diffstat (limited to 'src')
-rw-r--r--src/bard_music.c1
-rw-r--r--src/battle_records.c510
-rw-r--r--src/berry.c2
-rw-r--r--src/berry_blender.c20
-rw-r--r--src/berry_tag_screen.c6
-rw-r--r--src/bg.c4
-rw-r--r--src/field_camera.c6
-rw-r--r--src/field_map_obj.c2
-rw-r--r--src/fieldmap.c1034
-rw-r--r--src/item.c1027
-rw-r--r--src/item_icon.c2
-rwxr-xr-xsrc/item_menu.c40
-rw-r--r--src/item_menu_icons.c6
-rw-r--r--src/lilycove_lady.c4
-rw-r--r--src/load_save.c83
-rw-r--r--src/mail.c2
-rw-r--r--src/mauville_old_man.c1247
-rw-r--r--src/new_game.c12
-rw-r--r--src/overworld.c5
-rw-r--r--src/player_pc.c12
-rw-r--r--src/pokeblock.c2
-rw-r--r--src/pokemon_summary_screen.c4
-rw-r--r--src/random.c4
-rw-r--r--src/save.c31
-rw-r--r--src/secret_base.c2
-rw-r--r--src/trader.c209
-rw-r--r--src/tv.c30
27 files changed, 4091 insertions, 216 deletions
diff --git a/src/bard_music.c b/src/bard_music.c
index 6fb1496e5..6c2578071 100644
--- a/src/bard_music.c
+++ b/src/bard_music.c
@@ -2,6 +2,7 @@
// Includes
#include "global.h"
#include "bard_music.h"
+#include "constants/easy_chat.h"
#include "easy_chat.h"
#include "data/bard_music/bard_sounds.h"
diff --git a/src/battle_records.c b/src/battle_records.c
new file mode 100644
index 000000000..a148f998f
--- /dev/null
+++ b/src/battle_records.c
@@ -0,0 +1,510 @@
+#include "global.h"
+#include "battle_records.h"
+#include "bg.h"
+#include "window.h"
+#include "link.h"
+#include "battle.h"
+#include "overworld.h"
+#include "text.h"
+#include "text_window.h"
+#include "strings.h"
+#include "string_util.h"
+#include "trainer_card.h"
+#include "menu.h"
+#include "menu_helpers.h"
+#include "palette.h"
+#include "main.h"
+#include "scanline_effect.h"
+#include "international_string_util.h"
+#include "sound.h"
+#include "constants/songs.h"
+#include "malloc.h"
+#include "gpu_regs.h"
+#include "constants/game_stat.h"
+
+extern void PrintOnTrainerHillRecordsWindow(void); // pokenav.s
+
+// this file's functions
+static void Task_CloseTrainerHillRecordsOnButton(u8 taskId);
+static void Task_BeginPaletteFade(u8 taskId);
+static void Task_ExitTrainerHillRecords(u8 taskId);
+static void RemoveTrainerHillRecordsWindow(u8 windowId);
+static void CB2_ShowTrainerHillRecords(void);
+
+// EWRAM variables
+EWRAM_DATA u8 gRecordsWindowId = 0;
+EWRAM_DATA static u8 *sTilemapBuffer = NULL;
+
+// const rom data
+static const u32 sTrainerHillWindowTileset[] = INCBIN_U32("graphics/unknown/unknown_5B3484.4bpp");
+static const u16 sTrainerHillWindowPalette[] = INCBIN_U16("graphics/unknown/unknown_5B3484.gbapal");
+static const u32 sTrainerHillWindowTilemap[] = INCBIN_U32("graphics/unknown/unknown_5B3564.bin");
+
+static const struct BgTemplate sTrainerHillRecordsBgTemplates[] =
+{
+ {
+ .bg = 0,
+ .charBaseIndex = 0,
+ .mapBaseIndex = 31,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 0,
+ .baseTile = 0
+ },
+ {
+ .bg = 3,
+ .charBaseIndex = 1,
+ .mapBaseIndex = 30,
+ .screenSize = 0,
+ .paletteMode = 0,
+ .priority = 3,
+ .baseTile = 0
+ }
+};
+
+static const struct WindowTemplate sTrainerHillRecordsWindowTemplates[] =
+{
+ {0x0, 0x2, 0x1, 0x1A, 0x12, 0xF, 0x14},
+ DUMMY_WIN_TEMPLATE
+};
+
+static const struct WindowTemplate sLinkBattleRecordsWindow = {0x0, 0x2, 0x1, 0x1A, 0x11, 0xF, 0x1};
+
+static const u8 sText_DashesNoPlayer[] = _("-------");
+static const u8 sText_DashesNoScore[] = _("----");
+
+// code
+static void ClearLinkBattleRecord(struct LinkBattleRecord *record)
+{
+ CpuFill16(0, record, sizeof(struct LinkBattleRecord));
+ record->name[0] = EOS;
+ record->trainerId = 0;
+ record->wins = 0;
+ record->losses = 0;
+ record->draws = 0;
+}
+
+static void ClearLinkBattleRecords(struct LinkBattleRecord *records)
+{
+ s32 i;
+ for (i = 0; i < LINK_B_RECORDS_COUNT; i++)
+ {
+ ClearLinkBattleRecord(records + i);
+ }
+ SetGameStat(GAME_STAT_LINK_BATTLE_WINS, 0);
+ SetGameStat(GAME_STAT_LINK_BATTLE_LOSSES, 0);
+ SetGameStat(GAME_STAT_LINK_BATTLE_DRAWS, 0);
+}
+
+static s32 GetLinkBattleRecordTotalBattles(struct LinkBattleRecord *record)
+{
+ return record->wins + record->losses + record->draws;
+}
+
+static s32 FindLinkBattleRecord(struct LinkBattleRecord *records, const u8 *name, u16 trainerId)
+{
+ s32 i;
+
+ for (i = 0; i < LINK_B_RECORDS_COUNT; i++)
+ {
+ if (!StringCompareN(records[i].name, name, OT_NAME_LENGTH) && records[i].trainerId == trainerId)
+ return i;
+ }
+
+ return LINK_B_RECORDS_COUNT;
+}
+
+static void SortLinkBattleRecords(struct LinkBattleRecords *records)
+{
+ s32 i, j;
+
+ for (i = LINK_B_RECORDS_COUNT - 1; i > 0; i--)
+ {
+ for (j = i - 1; j >= 0; j--)
+ {
+ s32 totalBattlesI = GetLinkBattleRecordTotalBattles(&records->entries[i]);
+ s32 totalBattlesJ = GetLinkBattleRecordTotalBattles(&records->entries[j]);
+
+ if (totalBattlesI > totalBattlesJ)
+ {
+ struct LinkBattleRecord temp1;
+ u8 temp2;
+
+ temp1 = records->entries[i];
+ records->entries[i] = records->entries[j];
+ records->entries[j] = temp1;
+
+ temp2 = records->languages[i];
+ records->languages[i] = records->languages[j];
+ records->languages[j] = temp2;
+ }
+ }
+ }
+}
+
+static void UpdateLinkBattleRecord(struct LinkBattleRecord *record, s32 battleOutcome)
+{
+ switch (battleOutcome)
+ {
+ case B_OUTCOME_WON:
+ record->wins++;
+ if (record->wins > 9999)
+ record->wins = 9999;
+ break;
+ case B_OUTCOME_LOST:
+ record->losses++;
+ if (record->losses > 9999)
+ record->losses = 9999;
+ break;
+ case B_OUTCOME_DREW:
+ record->draws++;
+ if (record->draws > 9999)
+ record->draws = 9999;
+ break;
+ }
+}
+
+static void UpdateLinkBattleGameStats(s32 battleOutcome)
+{
+ u8 stat;
+
+ switch (battleOutcome)
+ {
+ case B_OUTCOME_WON:
+ stat = GAME_STAT_LINK_BATTLE_WINS;
+ break;
+ case B_OUTCOME_LOST:
+ stat = GAME_STAT_LINK_BATTLE_LOSSES;
+ break;
+ case B_OUTCOME_DREW:
+ stat = GAME_STAT_LINK_BATTLE_DRAWS;
+ break;
+ default:
+ return;
+ }
+
+ if (GetGameStat(stat) < 9999)
+ IncrementGameStat(stat);
+}
+
+static void UpdateLinkBattleRecords(struct LinkBattleRecords *records, const u8 *name, u16 trainerId, s32 battleOutcome, u8 battlerId)
+{
+ s32 index;
+
+ UpdateLinkBattleGameStats(battleOutcome);
+ SortLinkBattleRecords(records);
+ index = FindLinkBattleRecord(records->entries, name, trainerId);
+ if (index == LINK_B_RECORDS_COUNT)
+ {
+ index = LINK_B_RECORDS_COUNT - 1;
+ ClearLinkBattleRecord(&records->entries[index]);
+ StringCopyN(records->entries[index].name, name, OT_NAME_LENGTH);
+ records->entries[index].trainerId = trainerId;
+ records->languages[index] = gLinkPlayers[battlerId].language;
+ }
+ UpdateLinkBattleRecord(&records->entries[index], battleOutcome);
+ SortLinkBattleRecords(records);
+}
+
+void ClearPlayerLinkBattleRecords(void)
+{
+ ClearLinkBattleRecords(gSaveBlock1Ptr->linkBattleRecords.entries);
+}
+
+static void IncTrainerCardWins(s32 battlerId)
+{
+ u16 *wins = &gTrainerCards[battlerId].linkBattleWins;
+ (*wins)++;
+ if (*wins > 9999)
+ *wins = 9999;
+}
+
+static void IncTrainerCardLosses(s32 battlerId)
+{
+ u16 *losses = &gTrainerCards[battlerId].linkBattleLosses;
+ (*losses)++;
+ if (*losses > 9999)
+ *losses = 9999;
+}
+
+static void UpdateTrainerCardWinsLosses(s32 battlerId)
+{
+ switch (gBattleOutcome)
+ {
+ case B_OUTCOME_WON:
+ IncTrainerCardWins(BATTLE_OPPOSITE(battlerId));
+ IncTrainerCardLosses(battlerId);
+ break;
+ case B_OUTCOME_LOST:
+ IncTrainerCardLosses(BATTLE_OPPOSITE(battlerId));
+ IncTrainerCardWins(battlerId);
+ break;
+ }
+}
+
+void UpdatePlayerLinkBattleRecords(s32 battlerId)
+{
+ if (InUnionRoom() != TRUE)
+ {
+ UpdateTrainerCardWinsLosses(battlerId);
+ UpdateLinkBattleRecords(
+ &gSaveBlock1Ptr->linkBattleRecords,
+ gTrainerCards[battlerId].playerName,
+ gTrainerCards[battlerId].trainerId,
+ gBattleOutcome,
+ battlerId);
+ }
+}
+
+static void PrintLinkBattleWinsLossesDraws(struct LinkBattleRecord *records)
+{
+ s32 x;
+
+ ConvertIntToDecimalStringN(gStringVar1, GetGameStat(GAME_STAT_LINK_BATTLE_WINS), STR_CONV_MODE_LEFT_ALIGN, 4);
+ ConvertIntToDecimalStringN(gStringVar2, GetGameStat(GAME_STAT_LINK_BATTLE_LOSSES), STR_CONV_MODE_LEFT_ALIGN, 4);
+ ConvertIntToDecimalStringN(gStringVar3, GetGameStat(GAME_STAT_LINK_BATTLE_DRAWS), STR_CONV_MODE_LEFT_ALIGN, 4);
+ StringExpandPlaceholders(gStringVar4, gText_TotalRecordWLD);
+
+ x = GetStringCenterAlignXOffset(1, gStringVar4, 0xD0);
+ PrintTextOnWindow(gRecordsWindowId, 1, gStringVar4, x, 0x11, 0, NULL);
+}
+
+static void PrintLinkBattleRecord(struct LinkBattleRecord *record, u8 y, s32 language)
+{
+ if (record->wins == 0 && record->losses == 0 && record->draws == 0)
+ {
+ // empty slot
+ PrintTextOnWindow(gRecordsWindowId, 1, sText_DashesNoPlayer, 8, (y * 8) + 1, 0, NULL);
+ PrintTextOnWindow(gRecordsWindowId, 1, sText_DashesNoScore, 80, (y * 8) + 1, 0, NULL);
+ PrintTextOnWindow(gRecordsWindowId, 1, sText_DashesNoScore, 128, (y * 8) + 1, 0, NULL);
+ PrintTextOnWindow(gRecordsWindowId, 1, sText_DashesNoScore, 176, (y * 8) + 1, 0, NULL);
+ }
+ else
+ {
+ StringFillWithTerminator(gStringVar1, 8);
+ StringCopyN(gStringVar1, record->name, 7);
+ ConvertInternationalString(gStringVar1, language);
+
+ PrintTextOnWindow(gRecordsWindowId, 1, gStringVar1, 8, (y * 8) + 1, 0, NULL);
+
+ ConvertIntToDecimalStringN(gStringVar1, record->wins, STR_CONV_MODE_RIGHT_ALIGN, 4);
+ PrintTextOnWindow(gRecordsWindowId, 1, gStringVar1, 80, (y * 8) + 1, 0, NULL);
+
+ ConvertIntToDecimalStringN(gStringVar1, record->losses, STR_CONV_MODE_RIGHT_ALIGN, 4);
+ PrintTextOnWindow(gRecordsWindowId, 1, gStringVar1, 128, (y * 8) + 1, 0, NULL);
+
+ ConvertIntToDecimalStringN(gStringVar1, record->draws, STR_CONV_MODE_RIGHT_ALIGN, 4);
+ PrintTextOnWindow(gRecordsWindowId, 1, gStringVar1, 176, (y * 8) + 1, 0, NULL);
+ }
+}
+
+void ShowLinkBattleRecords(void)
+{
+ s32 i, x;
+
+ gRecordsWindowId = AddWindow(&sLinkBattleRecordsWindow);
+ NewMenuHelpers_DrawStdWindowFrame(gRecordsWindowId, FALSE);
+ FillWindowPixelBuffer(gRecordsWindowId, 0x11);
+ StringExpandPlaceholders(gStringVar4, gText_PlayersBattleResults);
+
+ x = GetStringCenterAlignXOffset(1, gStringVar4, 208);
+ PrintTextOnWindow(gRecordsWindowId, 1, gStringVar4, x, 1, 0, NULL);
+ PrintLinkBattleWinsLossesDraws(gSaveBlock1Ptr->linkBattleRecords.entries);
+
+ StringExpandPlaceholders(gStringVar4, gText_WinLoseDraw);
+ PrintTextOnWindow(gRecordsWindowId, 1, gStringVar4, 0, 41, 0, NULL);
+
+ for (i = 0; i < LINK_B_RECORDS_COUNT; i++)
+ {
+ PrintLinkBattleRecord(&gSaveBlock1Ptr->linkBattleRecords.entries[i], 7 + (i * 2), gSaveBlock1Ptr->linkBattleRecords.languages[i]);
+ }
+
+ PutWindowTilemap(gRecordsWindowId);
+ CopyWindowToVram(gRecordsWindowId, 3);
+}
+
+void RemoveRecordsWindow(void)
+{
+ sub_819746C(gRecordsWindowId, FALSE);
+ RemoveWindow(gRecordsWindowId);
+}
+
+static void Task_TrainerHillWaitForPaletteFade(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ gTasks[taskId].func = Task_CloseTrainerHillRecordsOnButton;
+}
+
+static void Task_CloseTrainerHillRecordsOnButton(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId];
+
+ if (gMain.newKeys & A_BUTTON || gMain.newKeys & B_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+ task->func = Task_BeginPaletteFade;
+ }
+}
+
+static void Task_BeginPaletteFade(u8 taskId)
+{
+ BeginNormalPaletteFade(-1, 0, 0, 0x10, 0);
+ gTasks[taskId].func = Task_ExitTrainerHillRecords;
+}
+
+static void Task_ExitTrainerHillRecords(u8 taskId)
+{
+ if (!gPaletteFade.active)
+ {
+ SetMainCallback2(CB2_ReturnToFieldContinueScript);
+ Free(sTilemapBuffer);
+ RemoveTrainerHillRecordsWindow(0);
+ FreeAllWindowBuffers();
+ DestroyTask(taskId);
+ }
+}
+
+static void RemoveTrainerHillRecordsWindow(u8 windowId)
+{
+ FillWindowPixelBuffer(windowId, 0);
+ ClearWindowTilemap(windowId);
+ CopyWindowToVram(windowId, 2);
+ RemoveWindow(windowId);
+}
+
+static void ClearVramOamPlttRegs(void)
+{
+ DmaClearLarge16(3, (void*)(VRAM), VRAM_SIZE, 0x1000);
+ DmaClear32(3, OAM, OAM_SIZE);
+ DmaClear16(3, PLTT, PLTT_SIZE);
+
+ SetGpuReg(REG_OFFSET_DISPCNT, 0);
+ SetGpuReg(REG_OFFSET_BG0CNT, 0);
+ SetGpuReg(REG_OFFSET_BG0HOFS, 0);
+ SetGpuReg(REG_OFFSET_BG0VOFS, 0);
+ SetGpuReg(REG_OFFSET_BG1CNT, 0);
+ SetGpuReg(REG_OFFSET_BG1HOFS, 0);
+ SetGpuReg(REG_OFFSET_BG1VOFS, 0);
+ SetGpuReg(REG_OFFSET_BG2CNT, 0);
+ SetGpuReg(REG_OFFSET_BG2HOFS, 0);
+ SetGpuReg(REG_OFFSET_BG2VOFS, 0);
+ SetGpuReg(REG_OFFSET_BG3CNT, 0);
+ SetGpuReg(REG_OFFSET_BG3HOFS, 0);
+ SetGpuReg(REG_OFFSET_BG3VOFS, 0);
+ SetGpuReg(REG_OFFSET_WIN0H, 0);
+ SetGpuReg(REG_OFFSET_WIN0V, 0);
+ SetGpuReg(REG_OFFSET_WININ, 0);
+ SetGpuReg(REG_OFFSET_WINOUT, 0);
+ SetGpuReg(REG_OFFSET_BLDCNT, 0);
+ SetGpuReg(REG_OFFSET_BLDALPHA, 0);
+ SetGpuReg(REG_OFFSET_BLDY, 0);
+}
+
+static void ClearTasksAndGraphicalStructs(void)
+{
+ ScanlineEffect_Stop();
+ ResetTasks();
+ ResetSpriteData();
+ ResetPaletteFade();
+ FreeAllSpritePalettes();
+}
+
+static void ResetBgCoordinates(void)
+{
+ ChangeBgX(0, 0, 0);
+ ChangeBgY(0, 0, 0);
+ ChangeBgX(1, 0, 0);
+ ChangeBgY(1, 0, 0);
+ ChangeBgX(2, 0, 0);
+ ChangeBgY(2, 0, 0);
+ ChangeBgX(3, 0, 0);
+ ChangeBgY(3, 0, 0);
+}
+
+static void SetDispcntReg(void)
+{
+ SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_BG0_ON | DISPCNT_BG3_ON | DISPCNT_OBJ_1D_MAP);
+}
+
+static void LoadTrainerHillRecordsWindowGfx(u8 bgId)
+{
+ LoadBgTiles(bgId, sTrainerHillWindowTileset, sizeof(sTrainerHillWindowTileset), 0);
+ CopyToBgTilemapBufferRect(bgId, sTrainerHillWindowTilemap, 0, 0, 0x20, 0x20);
+ LoadPalette(sTrainerHillWindowPalette, 0, 0x20);
+}
+
+static void VblankCB_TrainerHillRecords(void)
+{
+ LoadOam();
+ ProcessSpriteCopyRequests();
+ TransferPlttBuffer();
+}
+
+static void MainCB2_TrainerHillRecords(void)
+{
+ RunTasks();
+ AnimateSprites();
+ BuildOamBuffer();
+ UpdatePaletteFade();
+}
+
+void ShowTrainerHillRecords(void)
+{
+ SetVBlankCallback(NULL);
+ SetMainCallback2(CB2_ShowTrainerHillRecords);
+}
+
+static void CB2_ShowTrainerHillRecords(void)
+{
+ switch (gMain.state)
+ {
+ case 0:
+ SetVBlankCallback(NULL);
+ ClearVramOamPlttRegs();
+ gMain.state++;
+ break;
+ case 1:
+ ClearTasksAndGraphicalStructs();
+ gMain.state++;
+ break;
+ case 2:
+ sTilemapBuffer = AllocZeroed(0x800);
+ ResetBgsAndClearDma3BusyFlags(0);
+ InitBgsFromTemplates(0, sTrainerHillRecordsBgTemplates, ARRAY_COUNT(sTrainerHillRecordsBgTemplates));
+ SetBgTilemapBuffer(3, sTilemapBuffer);
+ ResetBgCoordinates();
+ gMain.state++;
+ break;
+ case 3:
+ LoadTrainerHillRecordsWindowGfx(3);
+ LoadPalette(stdpal_get(0), 0xF0, 0x20);
+ gMain.state++;
+ break;
+ case 4:
+ if (IsDma3ManagerBusyWithBgCopy() != TRUE)
+ {
+ ShowBg(0);
+ ShowBg(3);
+ CopyBgTilemapBufferToVram(3);
+ gMain.state++;
+ }
+ break;
+ case 5:
+ InitWindows(sTrainerHillRecordsWindowTemplates);
+ DeactivateAllTextPrinters();
+ gMain.state++;
+ break;
+ case 6:
+ BeginNormalPaletteFade(-1, 0, 0x10, 0, 0);
+ gMain.state++;
+ break;
+ case 7:
+ SetDispcntReg();
+ SetVBlankCallback(VblankCB_TrainerHillRecords);
+ PrintOnTrainerHillRecordsWindow();
+ CreateTask(Task_TrainerHillWaitForPaletteFade, 8);
+ SetMainCallback2(MainCB2_TrainerHillRecords);
+ gMain.state = 0;
+ break;
+ }
+}
diff --git a/src/berry.c b/src/berry.c
index 74b7090c0..e128eb0ec 100644
--- a/src/berry.c
+++ b/src/berry.c
@@ -1218,7 +1218,7 @@ void FieldObjectInteractionRemoveBerryTree(void)
u8 PlayerHasBerries(void)
{
- return IsBagPocketNonEmpty(BAG_BERRIES);
+ return IsBagPocketNonEmpty(POCKET_BERRIES);
}
void ResetBerryTreeSparkleFlags(void)
diff --git a/src/berry_blender.c b/src/berry_blender.c
index 9e6a0fef7..c3b0cc80d 100644
--- a/src/berry_blender.c
+++ b/src/berry_blender.c
@@ -30,6 +30,7 @@
#include "trig.h"
#include "tv.h"
#include "item_menu.h"
+#include "battle_records.h"
#define BLENDER_SCORE_BEST 0
#define BLENDER_SCORE_GOOD 1
@@ -131,7 +132,6 @@ extern struct MusicPlayerInfo gMPlayInfo_SE2;
extern struct MusicPlayerInfo gMPlayInfo_BGM;
extern u8 gInGameOpponentsNo;
extern u8 gUnknown_020322D5;
-extern u8 gResultsWindowId;
// graphics
extern const u8 gBerryBlenderArrowTiles[];
@@ -2472,7 +2472,7 @@ static void CB2_HandleBlenderEndGame(void)
sub_8081F94(&gSendCmd[0]);
if (sBerryBlenderData->yesNoAnswer == 0)
{
- if (IsBagPocketNonEmpty(BAG_BERRIES) == FALSE) // no berries
+ if (IsBagPocketNonEmpty(POCKET_BERRIES) == FALSE) // no berries
{
sBerryBlenderData->playAgainState = CANT_PLAY_NO_BERRIES;
gSendCmd[1] = 0x9999;
@@ -3485,13 +3485,13 @@ void ShowBerryBlenderRecordWindow(void)
u8 text[32];
winTemplate = sBlenderRecordWindowTemplate;
- gResultsWindowId = AddWindow(&winTemplate);
- NewMenuHelpers_DrawStdWindowFrame(gResultsWindowId, 0);
- FillWindowPixelBuffer(gResultsWindowId, 0x11);
+ gRecordsWindowId = AddWindow(&winTemplate);
+ NewMenuHelpers_DrawStdWindowFrame(gRecordsWindowId, 0);
+ FillWindowPixelBuffer(gRecordsWindowId, 0x11);
xPos = GetStringCenterAlignXOffset(1, gText_BlenderMaxSpeedRecord, 0x90);
- PrintTextOnWindow(gResultsWindowId, 1, gText_BlenderMaxSpeedRecord, xPos, 1, 0, NULL);
- PrintTextOnWindow(gResultsWindowId, 1, gText_234Players, 4, 0x29, 0, NULL);
+ PrintTextOnWindow(gRecordsWindowId, 1, gText_BlenderMaxSpeedRecord, xPos, 1, 0, NULL);
+ PrintTextOnWindow(gRecordsWindowId, 1, gText_234Players, 4, 0x29, 0, NULL);
for (i = 0, yPos = 0x29; i < BLENDER_SCORES_NO; i++)
{
@@ -3506,11 +3506,11 @@ void ShowBerryBlenderRecordWindow(void)
txtPtr = StringAppend(txtPtr, sText_RPM);
xPos = GetStringRightAlignXOffset(1, text, 0x8C);
- PrintTextOnWindow(gResultsWindowId, 1, text, xPos, yPos + (i * 16), 0, NULL);
+ PrintTextOnWindow(gRecordsWindowId, 1, text, xPos, yPos + (i * 16), 0, NULL);
}
- PutWindowTilemap(gResultsWindowId);
- CopyWindowToVram(gResultsWindowId, 3);
+ PutWindowTilemap(gRecordsWindowId);
+ CopyWindowToVram(gRecordsWindowId, 3);
}
static void sub_8083F3C(u8 taskId)
diff --git a/src/berry_tag_screen.c b/src/berry_tag_screen.c
index 1a0d1bce0..9a6e78c81 100644
--- a/src/berry_tag_screen.c
+++ b/src/berry_tag_screen.c
@@ -517,7 +517,7 @@ static void TryChangeDisplayedBerry(u8 taskId, s8 toMove)
s16 *data = gTasks[taskId].data;
s16 currPocketPosition = gUnknown_0203CE58.scrollPosition[3] + gUnknown_0203CE58.cursorPosition[3];
u32 newPocketPosition = currPocketPosition + toMove;
- if (newPocketPosition < 46 && BagGetItemIdByPocketPosition(BAG_BERRIES, newPocketPosition) != 0)
+ if (newPocketPosition < 46 && BagGetItemIdByPocketPosition(POCKET_BERRIES, newPocketPosition) != 0)
{
if (toMove < 0)
data[1] = 2;
@@ -537,7 +537,7 @@ static void HandleBagCursorPositionChange(s8 toMove)
u16 *cursorPos = &gUnknown_0203CE58.cursorPosition[3];
if (toMove > 0)
{
- if (*cursorPos < 4 || BagGetItemIdByPocketPosition(BAG_BERRIES, *scrollPos + 8) == 0)
+ if (*cursorPos < 4 || BagGetItemIdByPocketPosition(POCKET_BERRIES, *scrollPos + 8) == 0)
*cursorPos += toMove;
else
*scrollPos += toMove;
@@ -550,7 +550,7 @@ static void HandleBagCursorPositionChange(s8 toMove)
*scrollPos += toMove;
}
- sBerryTag->berryId = ItemIdToBerryType(BagGetItemIdByPocketPosition(BAG_BERRIES, *scrollPos + *cursorPos));
+ sBerryTag->berryId = ItemIdToBerryType(BagGetItemIdByPocketPosition(POCKET_BERRIES, *scrollPos + *cursorPos));
}
static void Task_DisplayAnotherBerry(u8 taskId)
diff --git a/src/bg.c b/src/bg.c
index 22861b64d..975c72a94 100644
--- a/src/bg.c
+++ b/src/bg.c
@@ -965,9 +965,9 @@ void CopyBgTilemapBufferToVram(u8 bg)
}
}
-void CopyToBgTilemapBufferRect(u8 bg, void* src, u8 destX, u8 destY, u8 width, u8 height)
+void CopyToBgTilemapBufferRect(u8 bg, const void* src, u8 destX, u8 destY, u8 width, u8 height)
{
- void* srcCopy;
+ const void* srcCopy;
u16 destX16;
u16 destY16;
u16 mode;
diff --git a/src/field_camera.c b/src/field_camera.c
index f653e0bf1..95167ee10 100644
--- a/src/field_camera.c
+++ b/src/field_camera.c
@@ -12,6 +12,8 @@
#include "sprite.h"
#include "text.h"
+EWRAM_DATA bool8 gUnusedBikeCameraAheadPanback = FALSE;
+
// Static type declarations
struct FieldCameraUnknownStruct
{
@@ -40,6 +42,10 @@ static IWRAM_DATA s16 gUnknown_03000E2A;
static IWRAM_DATA u8 gUnknown_03000E2C;
static IWRAM_DATA void (*gUnknown_03000E30)(void);
+struct CameraObject gUnknown_03005DD0;
+u16 gUnknown_03005DE8;
+u16 gUnknown_03005DEC;
+
// text
static void move_tilemap_camera_to_upper_left_corner_(struct FieldCameraUnknownStruct *a)
{
diff --git a/src/field_map_obj.c b/src/field_map_obj.c
index a5be62442..81cbe5210 100644
--- a/src/field_map_obj.c
+++ b/src/field_map_obj.c
@@ -1146,7 +1146,7 @@ const struct MapObjectGraphicsInfo *GetFieldObjectGraphicsInfo(u8 graphicsId)
}
if (graphicsId == 0x45)
{
- bard = sub_81201C8();
+ bard = GetCurrentMauvilleOldMan();
return gMauvilleOldManGraphicsInfoPointers[bard];
}
if (graphicsId >= NUM_OBJECT_GRAPHICS_INFO)
diff --git a/src/fieldmap.c b/src/fieldmap.c
new file mode 100644
index 000000000..245c88327
--- /dev/null
+++ b/src/fieldmap.c
@@ -0,0 +1,1034 @@
+#include "global.h"
+#include "overworld.h"
+#include "bg.h"
+#include "battle_frontier_2.h"
+#include "constants/rgb.h"
+#include "fieldmap.h"
+#include "fldeff_80F9BCC.h"
+#include "fldeff_cut.h"
+#include "fldeff_groundshake.h"
+#include "menu.h"
+#include "palette.h"
+#include "pokenav.h"
+#include "script.h"
+#include "secret_base.h"
+#include "tv.h"
+
+struct ConnectionFlags
+{
+ u8 south:1;
+ u8 north:1;
+ u8 west:1;
+ u8 east:1;
+};
+
+EWRAM_DATA static u16 gUnknown_02032318[0x2800] = {0};
+EWRAM_DATA struct MapHeader gMapHeader = {0};
+EWRAM_DATA struct Camera gCamera = {0};
+EWRAM_DATA static struct ConnectionFlags gUnknown_02037340 = {0};
+EWRAM_DATA static u32 sFiller_02037344 = 0; // without this, the next file won't align properly
+
+struct BackupMapData gUnknown_03005DC0;
+
+static const struct ConnectionFlags sDummyConnectionFlags = {0};
+
+struct MapHeader const *const mapconnection_get_mapheader(struct MapConnection *connection)
+{
+ return Overworld_GetMapHeaderByGroupAndId(connection->mapGroup, connection->mapNum);
+}
+
+void not_trainer_hill_battle_pyramid(void)
+{
+ mapheader_copy_mapdata_with_padding(&gMapHeader);
+ sub_80E8EE0(gMapHeader.events);
+ mapheader_run_script_with_tag_x1();
+}
+
+void sub_8087D74(void)
+{
+ mapheader_copy_mapdata_with_padding(&gMapHeader);
+ sub_80E9238(0);
+ sub_80E8EE0(gMapHeader.events);
+ mapdata_from_sav2();
+ mapheader_run_script_with_tag_x1();
+ UpdateTVScreensOnMap(gUnknown_03005DC0.width, gUnknown_03005DC0.height);
+}
+
+void battle_pyramid_map_load_related(u8 a0)
+{
+ CpuFastFill(0x03ff03ff, gUnknown_02032318, sizeof(gUnknown_02032318));
+ sub_81AA078(gUnknown_02032318, a0);
+}
+
+void trainer_hill_map_load_related(void)
+{
+ CpuFastFill(0x03ff03ff, gUnknown_02032318, sizeof(gUnknown_02032318));
+ sub_81D5FB4(gUnknown_02032318);
+}
+
+void mapheader_copy_mapdata_with_padding(struct MapHeader *mapHeader)
+{
+ struct MapData const *mapData;
+ int width;
+ int height;
+ mapData = mapHeader->mapData;
+ CpuFastFill16(0x03ff, gUnknown_02032318, sizeof(gUnknown_02032318));
+ gUnknown_03005DC0.map = gUnknown_02032318;
+ width = mapData->width + 15;
+ gUnknown_03005DC0.width = width;
+ height = mapData->height + 14;
+ gUnknown_03005DC0.height = height;
+ if (width * height <= 0x2800)
+ {
+ map_copy_with_padding(mapData->map, mapData->width, mapData->height);
+ mapheader_copy_mapdata_of_adjacent_maps(mapHeader);
+ }
+}
+
+void map_copy_with_padding(u16 *map, u16 width, u16 height)
+{
+ u16 *dest;
+ int y;
+ dest = gUnknown_03005DC0.map;
+ dest += gUnknown_03005DC0.width * 7 + 7;
+ for (y = 0; y < height; y++)
+ {
+ CpuCopy16(map, dest, width * 2);
+ dest += width + 0xf;
+ map += width;
+ }
+}
+
+void mapheader_copy_mapdata_of_adjacent_maps(struct MapHeader *mapHeader)
+{
+ int count;
+ struct MapConnection *connection;
+ int i;
+
+ if (mapHeader->connections)
+ {
+ count = mapHeader->connections->count;
+ connection = mapHeader->connections->connections;
+
+ gUnknown_02037340 = sDummyConnectionFlags;
+ for (i = 0; i < count; i++, connection++)
+ {
+ struct MapHeader const *cMap = mapconnection_get_mapheader(connection);
+ u32 offset = connection->offset;
+
+ switch (connection->direction)
+ {
+ case CONNECTION_SOUTH:
+ fillSouthConnection(mapHeader, cMap, offset);
+ gUnknown_02037340.south = 1;
+ break;
+ case CONNECTION_NORTH:
+ fillNorthConnection(mapHeader, cMap, offset);
+ gUnknown_02037340.north = 1;
+ break;
+ case CONNECTION_WEST:
+ fillWestConnection(mapHeader, cMap, offset);
+ gUnknown_02037340.west = 1;
+ break;
+ case CONNECTION_EAST:
+ fillEastConnection(mapHeader, cMap, offset);
+ gUnknown_02037340.east = 1;
+ break;
+ }
+ }
+ }
+}
+
+void sub_8087F54(int x, int y, struct MapHeader const *mapHeader, int x2, int y2, int width, int height)
+{
+ int i;
+ u16 *src;
+ u16 *dest;
+ int mapWidth;
+
+ mapWidth = mapHeader->mapData->width;
+ src = &mapHeader->mapData->map[mapWidth * y2 + x2];
+ dest = &gUnknown_03005DC0.map[gUnknown_03005DC0.width * y + x];
+
+ for (i = 0; i < height; i++)
+ {
+ CpuCopy16(src, dest, width * 2);
+ dest += gUnknown_03005DC0.width;
+ src += mapWidth;
+ }
+}
+
+void fillSouthConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset)
+{
+ int x, y;
+ int x2;
+ int width;
+ int cWidth;
+
+ if (connectedMapHeader)
+ {
+ cWidth = connectedMapHeader->mapData->width;
+ x = offset + 7;
+ y = mapHeader->mapData->height + 7;
+ if (x < 0)
+ {
+ x2 = -x;
+ x += cWidth;
+ if (x < gUnknown_03005DC0.width)
+ {
+ width = x;
+ }
+ else
+ {
+ width = gUnknown_03005DC0.width;
+ }
+ x = 0;
+ }
+ else
+ {
+ x2 = 0;
+ if (x + cWidth < gUnknown_03005DC0.width)
+ {
+ width = cWidth;
+ }
+ else
+ {
+ width = gUnknown_03005DC0.width - x;
+ }
+ }
+
+ sub_8087F54(
+ x, y,
+ connectedMapHeader,
+ x2, /*y2*/ 0,
+ width, /*height*/ 7);
+ }
+}
+
+void fillNorthConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset)
+{
+ int x;
+ int x2, y2;
+ int width;
+ int cWidth, cHeight;
+
+ if (connectedMapHeader)
+ {
+ cWidth = connectedMapHeader->mapData->width;
+ cHeight = connectedMapHeader->mapData->height;
+ x = offset + 7;
+ y2 = cHeight - 7;
+ if (x < 0)
+ {
+ x2 = -x;
+ x += cWidth;
+ if (x < gUnknown_03005DC0.width)
+ {
+ width = x;
+ }
+ else
+ {
+ width = gUnknown_03005DC0.width;
+ }
+ x = 0;
+ }
+ else
+ {
+ x2 = 0;
+ if (x + cWidth < gUnknown_03005DC0.width)
+ {
+ width = cWidth;
+ }
+ else
+ {
+ width = gUnknown_03005DC0.width - x;
+ }
+ }
+
+ sub_8087F54(
+ x, /*y*/ 0,
+ connectedMapHeader,
+ x2, y2,
+ width, /*height*/ 7);
+
+ }
+}
+
+void fillWestConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset)
+{
+ int y;
+ int x2, y2;
+ int height;
+ int cWidth, cHeight;
+ if (connectedMapHeader)
+ {
+ cWidth = connectedMapHeader->mapData->width;
+ cHeight = connectedMapHeader->mapData->height;
+ y = offset + 7;
+ x2 = cWidth - 7;
+ if (y < 0)
+ {
+ y2 = -y;
+ if (y + cHeight < gUnknown_03005DC0.height)
+ {
+ height = y + cHeight;
+ }
+ else
+ {
+ height = gUnknown_03005DC0.height;
+ }
+ y = 0;
+ }
+ else
+ {
+ y2 = 0;
+ if (y + cHeight < gUnknown_03005DC0.height)
+ {
+ height = cHeight;
+ }
+ else
+ {
+ height = gUnknown_03005DC0.height - y;
+ }
+ }
+
+ sub_8087F54(
+ /*x*/ 0, y,
+ connectedMapHeader,
+ x2, y2,
+ /*width*/ 7, height);
+ }
+}
+
+void fillEastConnection(struct MapHeader const *mapHeader, struct MapHeader const *connectedMapHeader, s32 offset)
+{
+ int x, y;
+ int y2;
+ int height;
+ int cHeight;
+ if (connectedMapHeader)
+ {
+ cHeight = connectedMapHeader->mapData->height;
+ x = mapHeader->mapData->width + 7;
+ y = offset + 7;
+ if (y < 0)
+ {
+ y2 = -y;
+ if (y + cHeight < gUnknown_03005DC0.height)
+ {
+ height = y + cHeight;
+ }
+ else
+ {
+ height = gUnknown_03005DC0.height;
+ }
+ y = 0;
+ }
+ else
+ {
+ y2 = 0;
+ if (y + cHeight < gUnknown_03005DC0.height)
+ {
+ height = cHeight;
+ }
+ else
+ {
+ height = gUnknown_03005DC0.height - y;
+ }
+ }
+
+ sub_8087F54(
+ x, y,
+ connectedMapHeader,
+ /*x2*/ 0, y2,
+ /*width*/ 8, height);
+ }
+}
+
+union Block
+{
+ struct
+ {
+ u16 block:10;
+ u16 collision:2;
+ u16 elevation:4;
+ } block;
+ u16 value;
+};
+
+u8 MapGridGetZCoordAt(int x, int y)
+{
+ u16 block;
+ int i;
+ u16 *border;
+
+ if (x >= 0 && x < gUnknown_03005DC0.width
+ && y >= 0 && y < gUnknown_03005DC0.height)
+ {
+ block = gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y];
+ }
+ else
+ {
+ border = gMapHeader.mapData->border;
+ i = (x + 1) & 1;
+ i += ((y + 1) & 1) * 2;
+ block = gMapHeader.mapData->border[i];
+ block |= 0xc00;
+ }
+
+ if (block == 0x3ff)
+ {
+ return 0;
+ }
+
+ return block >> 12;
+}
+
+u8 MapGridIsImpassableAt(int x, int y)
+{
+ u16 block;
+ int i;
+ u16 *border;
+
+ if (x >= 0 && x < gUnknown_03005DC0.width
+ && y >= 0 && y < gUnknown_03005DC0.height)
+ {
+ block = gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y];
+ }
+ else
+ {
+ border = gMapHeader.mapData->border;
+ i = (x + 1) & 1;
+ i += ((y + 1) & 1) * 2;
+ block = gMapHeader.mapData->border[i];
+ block |= 0xc00;
+ }
+ if (block == 0x3ff)
+ {
+ return 1;
+ }
+ return (block & 0xc00) >> 10;
+}
+
+u32 MapGridGetMetatileIdAt(int x, int y)
+{
+ u16 block;
+ int i;
+ int j;
+ struct MapData const *mapData;
+ u16 *border;
+ u16 block2;
+
+ if (x >= 0 && x < gUnknown_03005DC0.width
+ && y >= 0 && y < gUnknown_03005DC0.height)
+ {
+ block = gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y];
+ }
+ else
+ {
+ mapData = gMapHeader.mapData;
+ i = (x + 1) & 1;
+ i += ((y + 1) & 1) * 2;
+ block = mapData->border[i] | 0xc00;
+ }
+ if (block == 0x3ff)
+ {
+ border = gMapHeader.mapData->border;
+ j = (x + 1) & 1;
+ j += ((y + 1) & 1) * 2;
+ block2 = gMapHeader.mapData->border[j];
+ block2 |= 0xc00;
+ return block2 & block;
+ }
+ return block & 0x3ff;
+}
+
+u32 MapGridGetMetatileBehaviorAt(int x, int y)
+{
+ u16 metatile;
+ metatile = MapGridGetMetatileIdAt(x, y);
+ return GetBehaviorByMetatileId(metatile) & 0xff;
+}
+
+u8 MapGridGetMetatileLayerTypeAt(int x, int y)
+{
+ u16 metatile;
+ metatile = MapGridGetMetatileIdAt(x, y);
+ return (GetBehaviorByMetatileId(metatile) & 0xf000) >> 12;
+}
+
+void MapGridSetMetatileIdAt(int x, int y, u16 metatile)
+{
+ int i;
+ if (x >= 0 && x < gUnknown_03005DC0.width
+ && y >= 0 && y < gUnknown_03005DC0.height)
+ {
+ i = x + y * gUnknown_03005DC0.width;
+ gUnknown_03005DC0.map[i] = (gUnknown_03005DC0.map[i] & 0xf000) | (metatile & 0xfff);
+ }
+}
+
+void MapGridSetMetatileEntryAt(int x, int y, u16 metatile)
+{
+ int i;
+ if (x >= 0 && x < gUnknown_03005DC0.width
+ && y >= 0 && y < gUnknown_03005DC0.height)
+ {
+ i = x + gUnknown_03005DC0.width * y;
+ gUnknown_03005DC0.map[i] = metatile;
+ }
+}
+
+u16 GetBehaviorByMetatileId(u16 metatile)
+{
+ u16 *attributes;
+ if (metatile <= 0x1ff)
+ {
+ attributes = gMapHeader.mapData->primaryTileset->metatileAttributes;
+ return attributes[metatile];
+ }
+ else if (metatile <= 0x3ff)
+ {
+ attributes = gMapHeader.mapData->secondaryTileset->metatileAttributes;
+ return attributes[metatile - 0x200];
+ }
+ else
+ {
+ return 0xff;
+ }
+}
+
+void save_serialize_map(void)
+{
+ int i, j;
+ int x, y;
+ u16 *mapView;
+ int width;
+ mapView = gSaveBlock1Ptr->mapView;
+ width = gUnknown_03005DC0.width;
+ x = gSaveBlock1Ptr->pos.x;
+ y = gSaveBlock1Ptr->pos.y;
+ for (i = y; i < y + 14; i++)
+ {
+ for (j = x; j < x + 15; j++)
+ {
+ *mapView++ = gUnknown_02032318[width * i + j];
+ }
+ }
+}
+
+int sub_8088438(void)
+{
+ u16 i;
+ u32 r2;
+ r2 = 0;
+ for (i = 0; i < 0x200; i++)
+ {
+ r2 |= gSaveBlock1Ptr->mapView[i];
+ }
+ if (r2 == 0)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+void sav2_mapdata_clear(void)
+{
+ CpuFill16(0, gSaveBlock1Ptr->mapView, sizeof(gSaveBlock1Ptr->mapView));
+}
+
+void mapdata_from_sav2(void)
+{
+ u8 a0;
+ int i, j;
+ int x, y;
+ u16 *mapView;
+ int width;
+ mapView = gSaveBlock1Ptr->mapView;
+ if (!sub_8088438())
+ {
+ width = gUnknown_03005DC0.width;
+ x = gSaveBlock1Ptr->pos.x;
+ y = gSaveBlock1Ptr->pos.y;
+ for (i = y; i < y + 14; i++)
+ {
+ if (i == y && i != 0)
+ a0 = 0;
+ else if (i == y + 13 && i != gMapHeader.mapData->height - 1)
+ a0 = 1;
+ else
+ a0 = -1;
+
+ for (j = x; j < x + 15; j++)
+ {
+ if (!sub_8088BF0(&gUnknown_02032318[j + width * i], width, a0))
+ gUnknown_02032318[j + width * i] = *mapView;
+ mapView++;
+ }
+ }
+ for (j = x; j < x + 15; j++)
+ {
+ if (y != 0)
+ sub_80D423C(j, y - 1);
+ if (i < gMapHeader.mapData->height - 1)
+ sub_80D42B8(j, y + 13);
+ }
+ sav2_mapdata_clear();
+ }
+}
+
+void sub_80885C4(u8 a1)
+{
+ int width;
+ u16 *mapView;
+ int x0, y0;
+ int x2, y2;
+ u16 *src, *dest;
+ int srci, desti;
+ int r9, r8;
+ int x, y;
+ int i, j;
+ mapView = gSaveBlock1Ptr->mapView;
+ width = gUnknown_03005DC0.width;
+ r9 = 0;
+ r8 = 0;
+ x0 = gSaveBlock1Ptr->pos.x;
+ y0 = gSaveBlock1Ptr->pos.y;
+ x2 = 15;
+ y2 = 14;
+ switch (a1)
+ {
+ case CONNECTION_NORTH:
+ y0 += 1;
+ y2 = 13;
+ break;
+ case CONNECTION_SOUTH:
+ r8 = 1;
+ y2 = 13;
+ break;
+ case CONNECTION_WEST:
+ x0 += 1;
+ x2 = 14;
+ break;
+ case CONNECTION_EAST:
+ r9 = 1;
+ x2 = 14;
+ break;
+ }
+ for (y = 0; y < y2; y++)
+ {
+ i = 0;
+ j = 0;
+ for (x = 0; x < x2; x++)
+ {
+ desti = width * (y + y0);
+ srci = (y + r8) * 15 + r9;
+ src = &mapView[srci + i];
+ dest = &gUnknown_02032318[x0 + desti + j];
+ *dest = *src;
+ i++;
+ j++;
+ }
+ }
+ sav2_mapdata_clear();
+}
+
+int GetMapBorderIdAt(int x, int y)
+{
+ struct MapData const *mapData;
+ u16 block, block2;
+ int i, j;
+ if (x >= 0 && x < gUnknown_03005DC0.width
+ && y >= 0 && y < gUnknown_03005DC0.height)
+ {
+ i = gUnknown_03005DC0.width;
+ i *= y;
+ block = gUnknown_03005DC0.map[x + i];
+ if (block == 0x3ff)
+ {
+ goto fail;
+ }
+ }
+ else
+ {
+ mapData = gMapHeader.mapData;
+ j = (x + 1) & 1;
+ j += ((y + 1) & 1) * 2;
+ block2 = 0xc00 | mapData->border[j];
+ if (block2 == 0x3ff)
+ {
+ goto fail;
+ }
+ }
+ goto success;
+fail:
+ return -1;
+success:
+
+ if (x >= (gUnknown_03005DC0.width - 8))
+ {
+ if (!gUnknown_02037340.east)
+ {
+ return -1;
+ }
+ return CONNECTION_EAST;
+ }
+ else if (x < 7)
+ {
+ if (!gUnknown_02037340.west)
+ {
+ return -1;
+ }
+ return CONNECTION_WEST;
+ }
+ else if (y >= (gUnknown_03005DC0.height - 7))
+ {
+ if (!gUnknown_02037340.south)
+ {
+ return -1;
+ }
+ return CONNECTION_SOUTH;
+ }
+ else if (y < 7)
+ {
+ if (!gUnknown_02037340.north)
+ {
+ return -1;
+ }
+ return CONNECTION_NORTH;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int GetPostCameraMoveMapBorderId(int x, int y)
+{
+ return GetMapBorderIdAt(gSaveBlock1Ptr->pos.x + 7 + x, gSaveBlock1Ptr->pos.y + 7 + y);
+}
+
+int CanCameraMoveInDirection(int direction)
+{
+ int x, y;
+ x = gSaveBlock1Ptr->pos.x + 7 + gUnknown_08339D64[direction].x;
+ y = gSaveBlock1Ptr->pos.y + 7 + gUnknown_08339D64[direction].y;
+ if (GetMapBorderIdAt(x, y) == -1)
+ {
+ return 0;
+ }
+ return 1;
+}
+
+void sub_80887F8(struct MapConnection *connection, int direction, int x, int y)
+{
+ struct MapHeader const *mapHeader;
+ mapHeader = mapconnection_get_mapheader(connection);
+ switch (direction)
+ {
+ case CONNECTION_EAST:
+ gSaveBlock1Ptr->pos.x = -x;
+ gSaveBlock1Ptr->pos.y -= connection->offset;
+ break;
+ case CONNECTION_WEST:
+ gSaveBlock1Ptr->pos.x = mapHeader->mapData->width;
+ gSaveBlock1Ptr->pos.y -= connection->offset;
+ break;
+ case CONNECTION_SOUTH:
+ gSaveBlock1Ptr->pos.x -= connection->offset;
+ gSaveBlock1Ptr->pos.y = -y;
+ break;
+ case CONNECTION_NORTH:
+ gSaveBlock1Ptr->pos.x -= connection->offset;
+ gSaveBlock1Ptr->pos.y = mapHeader->mapData->height;
+ break;
+ }
+}
+
+bool8 CameraMove(int x, int y)
+{
+ unsigned int direction;
+ struct MapConnection *connection;
+ int old_x, old_y;
+ gCamera.active = FALSE;
+ direction = GetPostCameraMoveMapBorderId(x, y);
+ if (direction + 1 <= 1)
+ {
+ gSaveBlock1Ptr->pos.x += x;
+ gSaveBlock1Ptr->pos.y += y;
+ }
+ else
+ {
+ save_serialize_map();
+ sub_81BE72C();
+ old_x = gSaveBlock1Ptr->pos.x;
+ old_y = gSaveBlock1Ptr->pos.y;
+ connection = sub_8088950(direction, gSaveBlock1Ptr->pos.x, gSaveBlock1Ptr->pos.y);
+ sub_80887F8(connection, direction, x, y);
+ mliX_load_map(connection->mapGroup, connection->mapNum);
+ gCamera.active = TRUE;
+ gCamera.x = old_x - gSaveBlock1Ptr->pos.x;
+ gCamera.y = old_y - gSaveBlock1Ptr->pos.y;
+ gSaveBlock1Ptr->pos.x += x;
+ gSaveBlock1Ptr->pos.y += y;
+ sub_80885C4(direction);
+ }
+ return gCamera.active;
+}
+
+struct MapConnection *sub_8088950(u8 direction, int x, int y)
+{
+ int count;
+ struct MapConnection *connection;
+ int i;
+ count = gMapHeader.connections->count;
+ connection = gMapHeader.connections->connections;
+ for (i = 0; i < count; i++, connection++)
+ {
+ if (connection->direction == direction && sub_80889A8(direction, x, y, connection) == TRUE)
+ return connection;
+ }
+ return NULL;
+}
+
+bool8 sub_80889A8(u8 direction, int x, int y, struct MapConnection *connection)
+{
+ struct MapHeader const *mapHeader;
+ mapHeader = mapconnection_get_mapheader(connection);
+ switch (direction)
+ {
+ case CONNECTION_SOUTH:
+ case CONNECTION_NORTH:
+ return sub_8088A0C(x, gMapHeader.mapData->width, mapHeader->mapData->width, connection->offset);
+ case CONNECTION_WEST:
+ case CONNECTION_EAST:
+ return sub_8088A0C(y, gMapHeader.mapData->height, mapHeader->mapData->height, connection->offset);
+ }
+ return FALSE;
+}
+
+bool8 sub_8088A0C(int x, int src_width, int dest_width, int offset)
+{
+ int offset2;
+ offset2 = offset;
+
+ if (offset2 < 0)
+ offset2 = 0;
+
+ if (dest_width + offset < src_width)
+ src_width = dest_width + offset;
+
+ if (offset2 <= x && x <= src_width)
+ return TRUE;
+
+ return FALSE;
+}
+
+int sub_8088A38(int x, int width)
+{
+ if (x >= 0 && x < width)
+ return TRUE;
+
+ return FALSE;
+}
+
+int sub_8088A4C(struct MapConnection *connection, int x, int y)
+{
+ struct MapHeader const *mapHeader;
+ mapHeader = mapconnection_get_mapheader(connection);
+ switch (connection->direction)
+ {
+ case CONNECTION_SOUTH:
+ case CONNECTION_NORTH:
+ return sub_8088A38(x - connection->offset, mapHeader->mapData->width);
+ case CONNECTION_WEST:
+ case CONNECTION_EAST:
+ return sub_8088A38(y - connection->offset, mapHeader->mapData->height);
+ }
+ return FALSE;
+}
+
+struct MapConnection *sub_8088A8C(s16 x, s16 y)
+{
+ int count;
+ struct MapConnection *connection;
+ int i;
+ u8 direction;
+ if (!gMapHeader.connections)
+ {
+ return NULL;
+ }
+ else
+ {
+ count = gMapHeader.connections->count;
+ connection = gMapHeader.connections->connections;
+ for (i = 0; i < count; i++, connection++)
+ {
+ direction = connection->direction;
+ if ((direction == CONNECTION_DIVE || direction == CONNECTION_EMERGE)
+ || (direction == CONNECTION_NORTH && y > 6)
+ || (direction == CONNECTION_SOUTH && y < gMapHeader.mapData->height + 7)
+ || (direction == CONNECTION_WEST && x > 6)
+ || (direction == CONNECTION_EAST && x < gMapHeader.mapData->width + 7))
+ {
+ continue;
+ }
+ if (sub_8088A4C(connection, x - 7, y - 7) == TRUE)
+ {
+ return connection;
+ }
+ }
+ }
+ return NULL;
+}
+
+void sub_8088B3C(u16 x, u16 y)
+{
+ gSaveBlock1Ptr->pos.x = x - 7;
+ gSaveBlock1Ptr->pos.y = y - 7;
+}
+
+void sav1_camera_get_focus_coords(u16 *x, u16 *y)
+{
+ *x = gSaveBlock1Ptr->pos.x + 7;
+ *y = gSaveBlock1Ptr->pos.y + 7;
+}
+
+void SetCameraCoords(u16 x, u16 y)
+{
+ gSaveBlock1Ptr->pos.x = x;
+ gSaveBlock1Ptr->pos.y = y;
+}
+
+void GetCameraCoords(u16 *x, u16 *y)
+{
+ *x = gSaveBlock1Ptr->pos.x;
+ *y = gSaveBlock1Ptr->pos.y;
+}
+
+void sub_8088B94(int x, int y, int a2)
+{
+ if (x >= 0 && x < gUnknown_03005DC0.width && y >= 0 && y < gUnknown_03005DC0.height)
+ {
+ if (a2 != 0)
+ gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y] |= 0xC00;
+ else
+ gUnknown_03005DC0.map[x + gUnknown_03005DC0.width * y] &= 0xF3FF;
+ }
+}
+
+bool8 sub_8088BF0(u16* a0, u16 a1, u8 a2)
+{
+ if (a2 == 0xFF)
+ return FALSE;
+
+ if (a2 == 0)
+ a0 -= a1;
+ else
+ a0 += a1;
+
+ if (sub_80FADE4(*a0 & 0x3FF, a2) == 1)
+ return TRUE;
+ return FALSE;
+}
+
+void copy_tileset_patterns_to_vram(struct Tileset const *tileset, u16 numTiles, u16 offset)
+{
+ if (tileset)
+ {
+ if (!tileset->isCompressed)
+ LoadBgTiles(2, tileset->tiles, numTiles * 32, offset);
+ else
+ decompress_and_copy_tile_data_to_vram(2, tileset->tiles, numTiles * 32, offset, 0);
+ }
+}
+
+void copy_tileset_patterns_to_vram2(struct Tileset const *tileset, u16 numTiles, u16 offset)
+{
+ if (tileset)
+ {
+ if (!tileset->isCompressed)
+ LoadBgTiles(2, tileset->tiles, numTiles * 32, offset);
+ else
+ copy_decompressed_tile_data_to_vram_autofree(2, tileset->tiles, numTiles * 32, offset, 0);
+ }
+}
+
+void nullsub_3(u16 a0, u16 a1)
+{
+
+}
+
+void nullsub_90(void)
+{
+
+}
+
+void apply_map_tileset_palette(struct Tileset const *tileset, u16 destOffset, u16 size)
+{
+ u16 black = RGB_BLACK;
+
+ if (tileset)
+ {
+ if (tileset->isSecondary == FALSE)
+ {
+ LoadPalette(&black, destOffset, 2);
+ LoadPalette(((u16*)tileset->palettes) + 1, destOffset + 1, size - 2);
+ nullsub_3(destOffset + 1, (size - 2) >> 1);
+ }
+ else if (tileset->isSecondary == TRUE)
+ {
+ LoadPalette(((u16*)tileset->palettes) + 0x60, destOffset, size);
+ nullsub_3(destOffset, size >> 1);
+ }
+ else
+ {
+ LoadCompressedPalette((u16*)tileset->palettes, destOffset, size);
+ nullsub_3(destOffset, size >> 1);
+ }
+ }
+}
+
+void copy_map_tileset1_to_vram(struct MapData const *mapData)
+{
+ copy_tileset_patterns_to_vram(mapData->primaryTileset, 0x200, 0);
+}
+
+void copy_map_tileset2_to_vram(struct MapData const *mapData)
+{
+ copy_tileset_patterns_to_vram(mapData->secondaryTileset, 0x200, 0x200);
+}
+
+void copy_map_tileset2_to_vram_2(struct MapData const *mapData)
+{
+ copy_tileset_patterns_to_vram2(mapData->secondaryTileset, 0x200, 0x200);
+}
+
+void apply_map_tileset1_palette(struct MapData const *mapData)
+{
+ apply_map_tileset_palette(mapData->primaryTileset, 0, 0xC0);
+}
+
+void apply_map_tileset2_palette(struct MapData const *mapData)
+{
+ apply_map_tileset_palette(mapData->secondaryTileset, 0x60, 0xE0);
+}
+
+void copy_map_tileset1_tileset2_to_vram(struct MapData const *mapData)
+{
+ if (mapData)
+ {
+ copy_tileset_patterns_to_vram2(mapData->primaryTileset, 0x200, 0);
+ copy_tileset_patterns_to_vram2(mapData->secondaryTileset, 0x200, 0x200);
+ }
+}
+
+void apply_map_tileset1_tileset2_palette(struct MapData const *mapData)
+{
+ if (mapData)
+ {
+ apply_map_tileset1_palette(mapData);
+ apply_map_tileset2_palette(mapData);
+ }
+}
diff --git a/src/item.c b/src/item.c
index 0c60c417d..975fef3ae 100644
--- a/src/item.c
+++ b/src/item.c
@@ -5,52 +5,48 @@
#include "string_util.h"
#include "text.h"
#include "event_data.h"
+#include "malloc.h"
+#include "secret_base.h"
+#include "item_menu.h"
+#include "strings.h"
+#include "load_save.h"
-extern void ApplyNewEncryptionKeyToHword(u16* hword, u32 newKey);
extern bool8 InBattlePyramid(void);
+extern u16 gUnknown_0203CF30[];
+extern const struct Item gItems[];
-extern const u8 gText_PokeBalls[];
-extern const u8 gText_Berries[];
-extern const u8 gText_Berry[];
+// this file's functions
+static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count);
+static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count);
-bool8 CheckPyramidBagHasItem(u16 itemId, u16 count);
-bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count);
+// EWRAM variables
+EWRAM_DATA struct BagPocket gBagPockets[POCKETS_COUNT] = {0};
-enum
-{
- ITEMS_POCKET,
- BALLS_POCKET,
- TMHM_POCKET,
- BERRIES_POCKET,
- KEYITEMS_POCKET
-};
-
-EWRAM_DATA struct BagPocket gBagPockets[5] = {};
-
-u16 GetBagItemQuantity(u16* quantity)
+// code
+static u16 GetBagItemQuantity(u16 *quantity)
{
return gSaveBlock2Ptr->encryptionKey ^ *quantity;
}
-void SetBagItemQuantity(u16* quantity, u16 newValue)
+static void SetBagItemQuantity(u16 *quantity, u16 newValue)
{
*quantity = newValue ^ gSaveBlock2Ptr->encryptionKey;
}
-u16 GetBagItemId(u16* slot)
+static u16 GetPCItemQuantity(u16 *quantity)
{
- return *slot;
+ return *quantity;
}
-void SetBagItemId(u16* slot, u16 newItemId)
+static void SetPCItemQuantity(u16 *quantity, u16 newValue)
{
- *slot = newItemId;
+ *quantity = newValue;
}
void ApplyNewEncryptionKeyToBagItems(u32 newKey)
{
u32 pocket, item;
- for (pocket = 0; pocket < 5; pocket++)
+ for (pocket = 0; pocket < POCKETS_COUNT; pocket++)
{
for (item = 0; item < gBagPockets[pocket].capacity; item++)
ApplyNewEncryptionKeyToHword(&(gBagPockets[pocket].itemSlots[item].quantity), newKey);
@@ -62,58 +58,57 @@ void ApplyNewEncryptionKeyToBagItems_(u32 newKey) // really GF?
ApplyNewEncryptionKeyToBagItems(newKey);
}
-// TODO: move those max values to defines
-
void SetBagItemsPointers(void)
{
gBagPockets[ITEMS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_Items;
- gBagPockets[ITEMS_POCKET].capacity = 30;
+ gBagPockets[ITEMS_POCKET].capacity = BAG_ITEMS_COUNT;
gBagPockets[KEYITEMS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_KeyItems;
- gBagPockets[KEYITEMS_POCKET].capacity = 30;
+ gBagPockets[KEYITEMS_POCKET].capacity = BAG_KEYITEMS_COUNT;
gBagPockets[BALLS_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_PokeBalls;
- gBagPockets[BALLS_POCKET].capacity = 16;
+ gBagPockets[BALLS_POCKET].capacity = BAG_POKEBALLS_COUNT;
gBagPockets[TMHM_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_TMHM;
- gBagPockets[TMHM_POCKET].capacity = 64;
+ gBagPockets[TMHM_POCKET].capacity = BAG_TMHM_COUNT;
gBagPockets[BERRIES_POCKET].itemSlots = gSaveBlock1Ptr->bagPocket_Berries;
- gBagPockets[BERRIES_POCKET].capacity = 46;
+ gBagPockets[BERRIES_POCKET].capacity = BAG_BERRIES_COUNT;
}
-void CopyItemName(u16 itemId, u8 *string)
+void CopyItemName(u16 itemId, u8 *dst)
{
- StringCopy(string, ItemId_GetItem(itemId)->name);
+ StringCopy(dst, ItemId_GetName(itemId));
}
-void CopyItemNameHandlePlural(u16 itemId, u8 *string, u32 quantity)
+void CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity)
{
if (itemId == ITEM_POKE_BALL)
{
if (quantity < 2)
- StringCopy(string, ItemId_GetItem(ITEM_POKE_BALL)->name);
+ StringCopy(dst, ItemId_GetName(ITEM_POKE_BALL));
else
- StringCopy(string, gText_PokeBalls);
+ StringCopy(dst, gText_PokeBalls);
}
else
{
if (itemId >= ITEM_CHERI_BERRY && itemId <= ITEM_ENIGMA_BERRY)
- GetBerryCountString(string, gBerries[itemId - ITEM_CHERI_BERRY].name, quantity);
+ GetBerryCountString(dst, gBerries[itemId - ITEM_CHERI_BERRY].name, quantity);
else
- StringCopy(string, ItemId_GetItem(itemId)->name);
+ StringCopy(dst, ItemId_GetName(itemId));
}
}
-void GetBerryCountString(u8* dst, const u8* berryName, u32 quantity)
+void GetBerryCountString(u8 *dst, const u8 *berryName, u32 quantity)
{
- const u8* berryString;
- u8* txtPtr;
+ const u8 *berryString;
+ u8 *txtPtr;
if (quantity < 2)
berryString = gText_Berry;
else
berryString = gText_Berries;
+
txtPtr = StringCopy(dst, berryName);
*txtPtr = CHAR_SPACE;
StringCopy(txtPtr + 1, berryString);
@@ -138,21 +133,21 @@ bool8 CheckBagHasItem(u16 itemId, u16 count)
if (ItemId_GetPocket(itemId) == 0)
return FALSE;
- if (InBattlePyramid() || FlagGet(0x4004) == TRUE)
+ if (InBattlePyramid() || FlagGet(FLAG_SPECIAL_FLAG_0x4004) == TRUE)
return CheckPyramidBagHasItem(itemId, count);
pocket = ItemId_GetPocket(itemId) - 1;
- //Check for item slots that contain the item
+ // Check for item slots that contain the item
for (i = 0; i < gBagPockets[pocket].capacity; i++)
{
if (gBagPockets[pocket].itemSlots[i].itemId == itemId)
{
u16 quantity;
- //Does this item slot contain enough of the item?
+ // Does this item slot contain enough of the item?
quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity);
if (quantity >= count)
return TRUE;
count -= quantity;
- //Does this item slot and all previous slots contain enough of the item?
+ // Does this item slot and all previous slots contain enough of the item?
if (count == 0)
return TRUE;
}
@@ -163,69 +158,945 @@ bool8 CheckBagHasItem(u16 itemId, u16 count)
bool8 HasAtLeastOneBerry(void)
{
u16 i;
- for (i = 0x85; i < 0xB3; i++)
+
+ for (i = FIRST_BERRY_INDEX; i < ITEM_BRIGHT_POWDER; i++)
{
if (CheckBagHasItem(i, 1) == TRUE)
{
- gSpecialVar_Result = 1;
+ gSpecialVar_Result = TRUE;
return TRUE;
}
}
- gSpecialVar_Result = 0;
+ gSpecialVar_Result = FALSE;
return FALSE;
}
-/* Refuses to match.
+#ifdef NONMATCHING
+// Refuses to match.
bool8 CheckBagHasSpace(u16 itemId, u16 count)
{
u8 i;
- u8 pocket;
- u16 slotCapacity;
- u16 quantity;
- if (ItemId_GetPocket(itemId) == 0)
+ if (ItemId_GetPocket(itemId) == POCKET_NONE)
return FALSE;
- if (InBattlePyramid() || FlagGet(0x4004) == TRUE)
+
+ if (InBattlePyramid() || FlagGet(FLAG_SPECIAL_FLAG_0x4004) == TRUE)
+ {
return CheckPyramidBagHasSpace(itemId, count);
- pocket = ItemId_GetPocket(itemId) - 1;
- if (pocket != BERRIES_POCKET)
- slotCapacity = 99;
+ }
else
- slotCapacity = 999;
+ {
+ u8 pocket;
+ u16 slotCapacity;
+ u16 ownedCount;
- //Check space in any existing item slots that already contain this item
- for (i = 0; i < gBagPockets[pocket].capacity; i++)
+ pocket = ItemId_GetPocket(itemId) - 1;
+ if (pocket != BERRIES_POCKET)
+ slotCapacity = 99;
+ else
+ slotCapacity = 999;
+
+ // Check space in any existing item slots that already contain this item
+ for (i = 0; i < gBagPockets[pocket].capacity; i++)
+ {
+ if (gBagPockets[pocket].itemSlots[i].itemId == itemId)
+ {
+ ownedCount = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity);
+ if (ownedCount + count <= slotCapacity)
+ return TRUE;
+ if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET)
+ return FALSE;
+ count -= slotCapacity - ownedCount;
+ if (count == 0)
+ return TRUE;
+ }
+ }
+
+ // Check space in empty item slots
+ if (count > 0)
+ {
+ for (i = 0; i < gBagPockets[pocket].capacity; i++)
+ {
+ if (gBagPockets[pocket].itemSlots[i].itemId == 0)
+ {
+ if (count <= slotCapacity)
+ return TRUE;
+ if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET)
+ return FALSE;
+ count -= slotCapacity;
+ }
+ }
+ if (count > 0)
+ return FALSE; // No more item slots. The bag is full
+ }
+
+ return TRUE;
+ }
+}
+#else
+ASM_DIRECT
+bool8 CheckBagHasSpace(u16 itemId, u16 count)
+{
+ asm_unified("push {r4-r7,lr}\n\
+ mov r7, r10\n\
+ mov r6, r9\n\
+ mov r5, r8\n\
+ push {r5-r7}\n\
+ sub sp, 0x4\n\
+ lsls r0, 16\n\
+ lsrs r0, 16\n\
+ mov r8, r0\n\
+ lsls r1, 16\n\
+ lsrs r5, r1, 16\n\
+ bl ItemId_GetPocket\n\
+ lsls r0, 24\n\
+ cmp r0, 0\n\
+ beq _080D6906\n\
+ bl InBattlePyramid\n\
+ lsls r0, 24\n\
+ cmp r0, 0\n\
+ bne _080D6838\n\
+ ldr r0, =0x00004004\n\
+ bl FlagGet\n\
+ lsls r0, 24\n\
+ lsrs r0, 24\n\
+ cmp r0, 0x1\n\
+ bne _080D684C\n\
+_080D6838:\n\
+ mov r0, r8\n\
+ adds r1, r5, 0\n\
+ bl CheckPyramidBagHasSpace\n\
+ lsls r0, 24\n\
+ lsrs r0, 24\n\
+ b _080D6916\n\
+ .pool\n\
+_080D684C:\n\
+ mov r0, r8\n\
+ bl ItemId_GetPocket\n\
+ subs r0, 0x1\n\
+ lsls r0, 24\n\
+ lsrs r2, r0, 24\n\
+ ldr r7, =0x000003e7\n\
+ cmp r2, 0x3\n\
+ beq _080D6860\n\
+ movs r7, 0x63\n\
+_080D6860:\n\
+ movs r6, 0\n\
+ ldr r1, =gBagPockets\n\
+ lsls r4, r2, 3\n\
+ adds r0, r4, r1\n\
+ mov r9, r4\n\
+ ldrb r0, [r0, 0x4]\n\
+ cmp r6, r0\n\
+ bcs _080D68BC\n\
+ subs r0, r2, 0x2\n\
+ lsls r0, 24\n\
+ lsrs r0, 24\n\
+ mov r10, r0\n\
+_080D6878:\n\
+ adds r0, r4, r1\n\
+ ldr r1, [r0]\n\
+ lsls r0, r6, 2\n\
+ adds r1, r0, r1\n\
+ ldrh r0, [r1]\n\
+ cmp r0, r8\n\
+ bne _080D68AC\n\
+ adds r0, r1, 0x2\n\
+ str r2, [sp]\n\
+ bl GetBagItemQuantity\n\
+ lsls r0, 16\n\
+ lsrs r1, r0, 16\n\
+ adds r0, r1, r5\n\
+ ldr r2, [sp]\n\
+ cmp r0, r7\n\
+ ble _080D6914\n\
+ mov r0, r10\n\
+ cmp r0, 0x1\n\
+ bls _080D6906\n\
+ subs r0, r7, r1\n\
+ subs r0, r5, r0\n\
+ lsls r0, 16\n\
+ lsrs r5, r0, 16\n\
+ cmp r5, 0\n\
+ beq _080D6914\n\
+_080D68AC:\n\
+ adds r0, r6, 0x1\n\
+ lsls r0, 24\n\
+ lsrs r6, r0, 24\n\
+ ldr r1, =gBagPockets\n\
+ adds r0, r4, r1\n\
+ ldrb r0, [r0, 0x4]\n\
+ cmp r6, r0\n\
+ bcc _080D6878\n\
+_080D68BC:\n\
+ cmp r5, 0\n\
+ beq _080D6914\n\
+ movs r6, 0\n\
+ ldr r3, =gBagPockets\n\
+ mov r1, r9\n\
+ adds r0, r1, r3\n\
+ ldrb r0, [r0, 0x4]\n\
+ cmp r6, r0\n\
+ bcs _080D6902\n\
+ adds r4, r3, 0\n\
+ subs r0, r2, 0x2\n\
+ lsls r0, 24\n\
+ lsrs r2, r0, 24\n\
+_080D68D6:\n\
+ adds r0, r1, r4\n\
+ ldr r1, [r0]\n\
+ lsls r0, r6, 2\n\
+ adds r0, r1\n\
+ ldrh r0, [r0]\n\
+ cmp r0, 0\n\
+ bne _080D68F2\n\
+ cmp r5, r7\n\
+ bls _080D6914\n\
+ cmp r2, 0x1\n\
+ bls _080D6906\n\
+ subs r0, r5, r7\n\
+ lsls r0, 16\n\
+ lsrs r5, r0, 16\n\
+_080D68F2:\n\
+ adds r0, r6, 0x1\n\
+ lsls r0, 24\n\
+ lsrs r6, r0, 24\n\
+ mov r1, r9\n\
+ adds r0, r1, r3\n\
+ ldrb r0, [r0, 0x4]\n\
+ cmp r6, r0\n\
+ bcc _080D68D6\n\
+_080D6902:\n\
+ cmp r5, 0\n\
+ beq _080D6914\n\
+_080D6906:\n\
+ movs r0, 0\n\
+ b _080D6916\n\
+ .pool\n\
+_080D6914:\n\
+ movs r0, 0x1\n\
+_080D6916:\n\
+ add sp, 0x4\n\
+ pop {r3-r5}\n\
+ mov r8, r3\n\
+ mov r9, r4\n\
+ mov r10, r5\n\
+ pop {r4-r7}\n\
+ pop {r1}\n\
+ bx r1");
+}
+#endif // NONMATCHING
+
+bool8 AddBagItem(u16 itemId, u16 count)
+{
+ u8 i;
+
+ if (ItemId_GetPocket(itemId) == POCKET_NONE)
+ return FALSE;
+
+ // check Battle Pyramid Bag
+ if (InBattlePyramid() || FlagGet(FLAG_SPECIAL_FLAG_0x4004) == TRUE)
{
- if (gBagPockets[pocket].itemSlots[i].itemId == itemId)
+ return AddPyramidBagItem(itemId, count);
+ }
+ else
+ {
+ struct BagPocket *itemPocket;
+ struct ItemSlot *newItems;
+ u16 slotCapacity;
+ u16 ownedCount;
+ u8 pocket = ItemId_GetPocket(itemId) - 1;
+
+ itemPocket = &gBagPockets[pocket];
+ newItems = AllocZeroed(itemPocket->capacity * sizeof(struct ItemSlot));
+ memcpy(newItems, itemPocket->itemSlots, itemPocket->capacity * sizeof(struct ItemSlot));
+
+ if (pocket != BERRIES_POCKET)
+ slotCapacity = 99;
+ else
+ slotCapacity = 999;
+
+ for (i = 0; i < itemPocket->capacity; i++)
{
- quantity = GetBagItemQuantity(&gBagPockets[pocket].itemSlots[i].quantity);
- if (quantity + count <= slotCapacity)
- return TRUE;
- if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET)
+ if (newItems[i].itemId == itemId)
+ {
+ ownedCount = GetBagItemQuantity(&newItems[i].quantity);
+ // check if won't exceed max slot capacity
+ if (ownedCount + count <= slotCapacity)
+ {
+ // successfully added to already existing item's count
+ SetBagItemQuantity(&newItems[i].quantity, ownedCount + count);
+
+ // goto SUCCESS_ADD_ITEM;
+ // is equivalent but won't match
+
+ memcpy(itemPocket->itemSlots, newItems, itemPocket->capacity * sizeof(struct ItemSlot));
+ Free(newItems);
+ return TRUE;
+ }
+ else
+ {
+ // try creating another instance of the item if possible
+ if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET)
+ {
+ Free(newItems);
+ return FALSE;
+ }
+ else
+ {
+ count -= slotCapacity - ownedCount;
+ SetBagItemQuantity(&newItems[i].quantity, slotCapacity);
+ // don't create another instance of the item if it's at max slot capacity and count is equal to 0
+ if (count == 0)
+ {
+ goto SUCCESS_ADD_ITEM;
+ }
+ }
+ }
+ }
+ }
+
+ // we're done if quantity is equal to 0
+ if (count > 0)
+ {
+ // either no existing item was found or we have to create another instance, because the capacity was exceeded
+ for (i = 0; i < itemPocket->capacity; i++)
+ {
+ if (newItems[i].itemId == ITEM_NONE)
+ {
+ newItems[i].itemId = itemId;
+ if (count > slotCapacity)
+ {
+ // try creating a new slot with max capacity if duplicates are possible
+ if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET)
+ {
+ Free(newItems);
+ return FALSE;
+ }
+ count -= slotCapacity;
+ SetBagItemQuantity(&newItems[i].quantity, slotCapacity);
+ }
+ else
+ {
+ // created a new slot and added quantity
+ SetBagItemQuantity(&newItems[i].quantity, count);
+ goto SUCCESS_ADD_ITEM;
+ }
+ }
+ }
+
+ if (count > 0)
+ {
+ Free(newItems);
return FALSE;
- count -= slotCapacity - quantity;
+ }
+ }
+
+ SUCCESS_ADD_ITEM:
+ memcpy(itemPocket->itemSlots, newItems, itemPocket->capacity * sizeof(struct ItemSlot));
+ Free(newItems);
+ return TRUE;
+ }
+}
+
+bool8 RemoveBagItem(u16 itemId, u16 count)
+{
+ u8 i;
+ u16 totalQuantity = 0;
+
+ if (ItemId_GetPocket(itemId) == POCKET_NONE || itemId == ITEM_NONE)
+ return FALSE;
+
+ // check Battle Pyramid Bag
+ if (InBattlePyramid() || FlagGet(FLAG_SPECIAL_FLAG_0x4004) == TRUE)
+ {
+ return RemovePyramidBagItem(itemId, count);
+ }
+ else
+ {
+ u8 pocket;
+ u8 var;
+ u16 ownedCount;
+ struct BagPocket *itemPocket;
+
+ pocket = ItemId_GetPocket(itemId) - 1;
+ itemPocket = &gBagPockets[pocket];
+
+ for (i = 0; i < itemPocket->capacity; i++)
+ {
+ if (itemPocket->itemSlots[i].itemId == itemId)
+ totalQuantity += GetBagItemQuantity(&itemPocket->itemSlots[i].quantity);
+ }
+
+ if (totalQuantity < count)
+ return FALSE; // We don't have enough of the item
+
+ if (CurrentMapIsSecretBase() == TRUE)
+ {
+ VarSet(VAR_0x40EE, VarGet(VAR_0x40EE) | 0x200);
+ VarSet(VAR_0x40ED, itemId);
+ }
+
+ var = sub_81ABB2C(pocket);
+ if (itemPocket->capacity > var
+ && itemPocket->itemSlots[var].itemId == itemId)
+ {
+ ownedCount = GetBagItemQuantity(&itemPocket->itemSlots[var].quantity);
+ if (ownedCount >= count)
+ {
+ SetBagItemQuantity(&itemPocket->itemSlots[var].quantity, ownedCount - count);
+ count = 0;
+ }
+ else
+ {
+ count -= ownedCount;
+ SetBagItemQuantity(&itemPocket->itemSlots[var].quantity, 0);
+ }
+
+ if (GetBagItemQuantity(&itemPocket->itemSlots[var].quantity) == 0)
+ itemPocket->itemSlots[var].itemId = ITEM_NONE;
+
if (count == 0)
return TRUE;
}
+
+ for (i = 0; i < itemPocket->capacity; i++)
+ {
+ if (itemPocket->itemSlots[i].itemId == itemId)
+ {
+ ownedCount = GetBagItemQuantity(&itemPocket->itemSlots[i].quantity);
+ if (ownedCount >= count)
+ {
+ SetBagItemQuantity(&itemPocket->itemSlots[i].quantity, ownedCount - count);
+ count = 0;
+ }
+ else
+ {
+ count -= ownedCount;
+ SetBagItemQuantity(&itemPocket->itemSlots[i].quantity, 0);
+ }
+
+ if (GetBagItemQuantity(&itemPocket->itemSlots[i].quantity) == 0)
+ itemPocket->itemSlots[i].itemId = ITEM_NONE;
+
+ if (count == 0)
+ return TRUE;
+ }
+ }
+ return TRUE;
}
+}
- //Check space in empty item slots
- if (count > 0)
+u8 GetPocketByItemId(u16 itemId)
+{
+ return ItemId_GetPocket(itemId);
+}
+
+void ClearItemSlots(struct ItemSlot *itemSlots, u8 itemCount)
+{
+ u16 i;
+
+ for (i = 0; i < itemCount; i++)
{
- for (i = 0; i < gBagPockets[pocket].capacity; i++)
+ itemSlots[i].itemId = ITEM_NONE;
+ SetBagItemQuantity(&itemSlots[i].quantity, 0);
+ }
+}
+
+static s32 FindFreePCItemSlot(void)
+{
+ s8 i;
+
+ for (i = 0; i < PC_ITEMS_COUNT; i++)
+ {
+ if (gSaveBlock1Ptr->pcItems[i].itemId == ITEM_NONE)
+ return i;
+ }
+ return -1;
+}
+
+u8 CountUsedPCItemSlots(void)
+{
+ u8 usedSlots = 0;
+ u8 i;
+
+ for (i = 0; i < PC_ITEMS_COUNT; i++)
+ {
+ if (gSaveBlock1Ptr->pcItems[i].itemId != ITEM_NONE)
+ usedSlots++;
+ }
+ return usedSlots;
+}
+
+bool8 CheckPCHasItem(u16 itemId, u16 count)
+{
+ u8 i;
+
+ for (i = 0; i < PC_ITEMS_COUNT; i++)
+ {
+ if (gSaveBlock1Ptr->pcItems[i].itemId == itemId && GetPCItemQuantity(&gSaveBlock1Ptr->pcItems[i].quantity) >= count)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool8 AddPCItem(u16 itemId, u16 count)
+{
+ u8 i;
+ s8 freeSlot;
+ u16 ownedCount;
+ struct ItemSlot *newItems;
+
+ // Copy PC items
+ newItems = AllocZeroed(sizeof(gSaveBlock1Ptr->pcItems));
+ memcpy(newItems, gSaveBlock1Ptr->pcItems, sizeof(gSaveBlock1Ptr->pcItems));
+
+ // Use any item slots that already contain this item
+ for (i = 0; i < PC_ITEMS_COUNT; i++)
+ {
+ if (newItems[i].itemId == itemId)
{
- if (gBagPockets[pocket].itemSlots[i].itemId == 0)
+ ownedCount = GetPCItemQuantity(&newItems[i].quantity);
+ if (ownedCount + count <= 999)
{
- if (count <= slotCapacity)
- return TRUE;
- if (pocket == TMHM_POCKET || pocket == BERRIES_POCKET)
- return FALSE;
- count -= slotCapacity;
+ SetPCItemQuantity(&newItems[i].quantity, ownedCount + count);
+ memcpy(gSaveBlock1Ptr->pcItems, newItems, sizeof(gSaveBlock1Ptr->pcItems));
+ Free(newItems);
+ return TRUE;
+ }
+ count += ownedCount - 999;
+ SetPCItemQuantity(&newItems[i].quantity, 999);
+ if (count == 0)
+ {
+ memcpy(gSaveBlock1Ptr->pcItems, newItems, sizeof(gSaveBlock1Ptr->pcItems));
+ Free(newItems);
+ return TRUE;
}
}
- if (count > 0)
- return FALSE; //No more item slots. The bag is full
}
+ // Put any remaining items into a new item slot.
+ if (count > 0)
+ {
+ freeSlot = FindFreePCItemSlot();
+ if (freeSlot == -1)
+ {
+ Free(newItems);
+ return FALSE;
+ }
+ else
+ {
+ newItems[freeSlot].itemId = itemId;
+ SetPCItemQuantity(&newItems[freeSlot].quantity, count);
+ }
+ }
+
+ // Copy items back to the PC
+ memcpy(gSaveBlock1Ptr->pcItems, newItems, sizeof(gSaveBlock1Ptr->pcItems));
+ Free(newItems);
return TRUE;
-}*/
+}
+
+void RemovePCItem(u8 index, u16 count)
+{
+ // UB: should use GetPCItemQuantity and SetPCItemQuantity functions
+ gSaveBlock1Ptr->pcItems[index].quantity -= count;
+ if (gSaveBlock1Ptr->pcItems[index].quantity == 0)
+ {
+ gSaveBlock1Ptr->pcItems[index].itemId = ITEM_NONE;
+ CompactPCItems();
+ }
+}
+
+void CompactPCItems(void)
+{
+ u16 i;
+ u16 j;
+
+ for (i = 0; i < PC_ITEMS_COUNT - 1; i++)
+ {
+ for (j = i + 1; j < PC_ITEMS_COUNT; j++)
+ {
+ if (gSaveBlock1Ptr->pcItems[i].itemId == 0)
+ {
+ struct ItemSlot temp = gSaveBlock1Ptr->pcItems[i];
+ gSaveBlock1Ptr->pcItems[i] = gSaveBlock1Ptr->pcItems[j];
+ gSaveBlock1Ptr->pcItems[j] = temp;
+ }
+ }
+ }
+}
+
+void SwapRegisteredBike(void)
+{
+ switch (gSaveBlock1Ptr->registeredItem)
+ {
+ case ITEM_MACH_BIKE:
+ gSaveBlock1Ptr->registeredItem = ITEM_ACRO_BIKE;
+ break;
+ case ITEM_ACRO_BIKE:
+ gSaveBlock1Ptr->registeredItem = ITEM_MACH_BIKE;
+ break;
+ }
+}
+
+u16 BagGetItemIdByPocketPosition(u8 pocketId, u16 pocketPos)
+{
+ return gBagPockets[pocketId - 1].itemSlots[pocketPos].itemId;
+}
+
+u16 BagGetQuantityByPocketPosition(u8 pocketId, u16 pocketPos)
+{
+ return GetBagItemQuantity(&gBagPockets[pocketId - 1].itemSlots[pocketPos].quantity);
+}
+
+static void SwapItemSlots(struct ItemSlot *a, struct ItemSlot *b)
+{
+ struct ItemSlot temp = *a;
+ *a = *b;
+ *b = temp;
+}
+
+void CompactItemsInBagPocket(struct BagPocket *bagPocket)
+{
+ u16 i, j;
+
+ for (i = 0; i < bagPocket->capacity - 1; i++)
+ {
+ for (j = i + 1; j < bagPocket->capacity; j++)
+ {
+ if (GetBagItemQuantity(&bagPocket->itemSlots[i].quantity) == 0)
+ SwapItemSlots(&bagPocket->itemSlots[i], &bagPocket->itemSlots[j]);
+ }
+ }
+}
+
+void SortBerriesOrTMHMs(struct BagPocket *bagPocket)
+{
+ u16 i, j;
+
+ for (i = 0; i < bagPocket->capacity - 1; i++)
+ {
+ for (j = i + 1; j < bagPocket->capacity; j++)
+ {
+ if (GetBagItemQuantity(&bagPocket->itemSlots[i].quantity) != 0)
+ {
+ if (GetBagItemQuantity(&bagPocket->itemSlots[j].quantity) == 0)
+ continue;
+ if (bagPocket->itemSlots[i].itemId <= bagPocket->itemSlots[j].itemId)
+ continue;
+ }
+ SwapItemSlots(&bagPocket->itemSlots[i], &bagPocket->itemSlots[j]);
+ }
+ }
+}
+
+void MoveItemSlotInList(struct ItemSlot* itemSlots_, u32 from, u32 to_)
+{
+ // dumb assignments needed to match
+ struct ItemSlot *itemSlots = itemSlots_;
+ u32 to = to_;
+
+ if (from != to)
+ {
+ s16 i, count;
+ struct ItemSlot firstSlot = itemSlots[from];
+
+ if (to > from)
+ {
+ to--;
+ for (i = from, count = to; i < count; i++)
+ itemSlots[i] = itemSlots[i + 1];
+ }
+ else
+ {
+ for (i = from, count = to; i > count; i--)
+ itemSlots[i] = itemSlots[i - 1];
+ }
+ itemSlots[to] = firstSlot;
+ }
+}
+
+void ClearBag(void)
+{
+ u16 i;
+
+ for (i = 0; i < POCKETS_COUNT; i++)
+ {
+ ClearItemSlots(gBagPockets[i].itemSlots, gBagPockets[i].capacity);
+ }
+}
+
+u16 CountTotalItemQuantityInBag(u16 itemId)
+{
+ u16 i;
+ u16 ownedCount = 0;
+ struct BagPocket *bagPocket = &gBagPockets[ItemId_GetPocket(itemId) - 1];
+
+ for (i = 0; i < bagPocket->capacity; i++)
+ {
+ if (bagPocket->itemSlots[i].itemId == itemId)
+ ownedCount += GetBagItemQuantity(&bagPocket->itemSlots[i].quantity);
+ }
+
+ return ownedCount;
+}
+
+static bool8 CheckPyramidBagHasItem(u16 itemId, u16 count)
+{
+ u8 i;
+ u16 *items = gSaveBlock2Ptr->pyramidBag.itemId[gSaveBlock2Ptr->frontierChosenLvl];
+ u8 *quantities = gSaveBlock2Ptr->pyramidBag.quantity[gSaveBlock2Ptr->frontierChosenLvl];
+
+ for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++)
+ {
+ if (items[i] == itemId)
+ {
+ if (quantities[i] >= count)
+ return TRUE;
+
+ count -= quantities[i];
+ if (count == 0)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static bool8 CheckPyramidBagHasSpace(u16 itemId, u16 count)
+{
+ u8 i;
+ u16 *items = gSaveBlock2Ptr->pyramidBag.itemId[gSaveBlock2Ptr->frontierChosenLvl];
+ u8 *quantities = gSaveBlock2Ptr->pyramidBag.quantity[gSaveBlock2Ptr->frontierChosenLvl];
+
+ for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++)
+ {
+ if (items[i] == itemId || items[i] == ITEM_NONE)
+ {
+ if (quantities[i] + count <= 99)
+ return TRUE;
+
+ count = (quantities[i] + count) - 99;
+ if (count == 0)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+bool8 AddPyramidBagItem(u16 itemId, u16 count)
+{
+ u16 i;
+
+ u16 *items = gSaveBlock2Ptr->pyramidBag.itemId[gSaveBlock2Ptr->frontierChosenLvl];
+ u8 *quantities = gSaveBlock2Ptr->pyramidBag.quantity[gSaveBlock2Ptr->frontierChosenLvl];
+
+ u16 *newItems = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(u16));
+ u8 *newQuantities = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(u8));
+
+ memcpy(newItems, items, PYRAMID_BAG_ITEMS_COUNT * sizeof(u16));
+ memcpy(newQuantities, quantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(u8));
+
+ for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++)
+ {
+ if (newItems[i] == itemId && newQuantities[i] < 99)
+ {
+ newQuantities[i] += count;
+ if (newQuantities[i] > 99)
+ {
+ count = newQuantities[i] - 99;
+ newQuantities[i] = 99;
+ }
+ else
+ {
+ count = 0;
+ }
+
+ if (count == 0)
+ break;
+ }
+ }
+
+ if (count > 0)
+ {
+ for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++)
+ {
+ if (newItems[i] == ITEM_NONE)
+ {
+ newItems[i] = itemId;
+ newQuantities[i] = count;
+ if (newQuantities[i] > 99)
+ {
+ count = newQuantities[i] - 99;
+ newQuantities[i] = 99;
+ }
+ else
+ {
+ count = 0;
+ }
+
+ if (count == 0)
+ break;
+ }
+ }
+ }
+
+ if (count == 0)
+ {
+ memcpy(items, newItems, PYRAMID_BAG_ITEMS_COUNT * sizeof(u16));
+ memcpy(quantities, newQuantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(u8));
+ Free(newItems);
+ Free(newQuantities);
+ return TRUE;
+ }
+ else
+ {
+ Free(newItems);
+ Free(newQuantities);
+ return FALSE;
+ }
+}
+
+bool8 RemovePyramidBagItem(u16 itemId, u16 count)
+{
+ u16 i;
+
+ u16 *items = gSaveBlock2Ptr->pyramidBag.itemId[gSaveBlock2Ptr->frontierChosenLvl];
+ u8 *quantities = gSaveBlock2Ptr->pyramidBag.quantity[gSaveBlock2Ptr->frontierChosenLvl];
+
+ i = gUnknown_0203CF30[3] + gUnknown_0203CF30[4];
+ if (items[i] == itemId && quantities[i] >= count)
+ {
+ quantities[i] -= count;
+ if (quantities[i] == 0)
+ items[i] = ITEM_NONE;
+ return TRUE;
+ }
+ else
+ {
+ u16 *newItems = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(u16));
+ u8 *newQuantities = Alloc(PYRAMID_BAG_ITEMS_COUNT * sizeof(u8));
+
+ memcpy(newItems, items, PYRAMID_BAG_ITEMS_COUNT * sizeof(u16));
+ memcpy(newQuantities, quantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(u8));
+
+ for (i = 0; i < PYRAMID_BAG_ITEMS_COUNT; i++)
+ {
+ if (newItems[i] == itemId)
+ {
+ if (newQuantities[i] >= count)
+ {
+ newQuantities[i] -= count;
+ count = 0;
+ if (newQuantities[i] == 0)
+ newItems[i] = ITEM_NONE;
+ }
+ else
+ {
+ count -= newQuantities[i];
+ newQuantities[i] = 0;
+ newItems[i] = ITEM_NONE;
+ }
+
+ if (count == 0)
+ break;
+ }
+ }
+
+ if (count == 0)
+ {
+ memcpy(items, newItems, PYRAMID_BAG_ITEMS_COUNT * sizeof(u16));
+ memcpy(quantities, newQuantities, PYRAMID_BAG_ITEMS_COUNT * sizeof(u8));
+ Free(newItems);
+ Free(newQuantities);
+ return TRUE;
+ }
+ else
+ {
+ Free(newItems);
+ Free(newQuantities);
+ return FALSE;
+ }
+ }
+}
+
+static u16 SanitizeItemId(u16 itemId)
+{
+ if (itemId >= ITEM_LAST_ID + 1)
+ return ITEM_NONE;
+ else
+ return itemId;
+}
+
+const u8 *ItemId_GetName(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].name;
+}
+
+u16 ItemId_GetId(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].itemId;
+}
+
+u16 ItemId_GetPrice(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].price;
+}
+
+u8 ItemId_GetHoldEffect(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].holdEffect;
+}
+
+u8 ItemId_GetHoldEffectParam(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].holdEffectParam;
+}
+
+const u8 *ItemId_GetDescription(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].description;
+}
+
+u8 ItemId_GetImportance(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].importance;
+}
+
+// unused
+u8 ItemId_GetUnknownValue(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].unk19;
+}
+
+u8 ItemId_GetPocket(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].pocket;
+}
+
+u8 ItemId_GetType(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].type;
+}
+
+ItemUseFunc ItemId_GetFieldFunc(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].fieldUseFunc;
+}
+
+u8 ItemId_GetBattleUsage(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].battleUsage;
+}
+
+ItemUseFunc ItemId_GetBattleFunc(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].battleUseFunc;
+}
+
+u8 ItemId_GetSecondaryId(u16 itemId)
+{
+ return gItems[SanitizeItemId(itemId)].secondaryId;
+}
diff --git a/src/item_icon.c b/src/item_icon.c
index 4aaad9c31..d6fedf892 100644
--- a/src/item_icon.c
+++ b/src/item_icon.c
@@ -4,13 +4,13 @@
#include "sprite.h"
#include "decompress.h"
#include "constants/items.h"
+#include "data/item_icon_table.h"
// EWRAM vars
EWRAM_DATA void *gItemIconDecompressionBuffer = NULL;
EWRAM_DATA void *gItemIcon4x4Buffer = NULL;
// const rom data
-extern const void *const gItemIconTable[][2]; // todo: move to C file
static const struct OamData sOamData_ItemIcon =
{
diff --git a/src/item_menu.c b/src/item_menu.c
index 8c05f0828..d7edea301 100755
--- a/src/item_menu.c
+++ b/src/item_menu.c
@@ -72,7 +72,7 @@ void AddBagItemIconSprite(u16, u8);
void bag_menu_print_description_box_text(int);
void bag_menu_print_cursor(u8, u8);
void bag_menu_print(u8, u8, const u8*, u8, u8, u8, u8, u8, u8);
-bool8 itemid_is_unique(u16);
+bool8 ItemId_GetImportance(u16);
u16 BagGetQuantityByPocketPosition(u8, u16);
void sub_81AB89C(void);
void task_close_bag_menu_2(u8);
@@ -687,7 +687,7 @@ void sub_81AB520(u8 rboxId, int item_index_in_pocket, u8 a)
offset = GetStringRightAlignXOffset(7, gStringVar4, 0x77);
bag_menu_print(rboxId, 7, gStringVar4, offset, a, 0, 0, -1, 0);
}
- else if (gUnknown_0203CE58.pocket != 4 && (unique = itemid_is_unique(itemId)) == FALSE)
+ else if (gUnknown_0203CE58.pocket != 4 && (unique = ItemId_GetImportance(itemId)) == FALSE)
{
ConvertIntToDecimalStringN(gStringVar1, itemQuantity, 1, 2);
StringExpandPlaceholders(gStringVar4, gText_xVar1);
@@ -804,10 +804,10 @@ void sub_81AB9A8(u8 pocketId)
{
case 2:
case 3:
- sub_80D6FB4(pocket);
+ SortBerriesOrTMHMs(pocket);
break;
default:
- sub_80D6F64(pocket);
+ CompactItemsInBagPocket(pocket);
break;
}
gUnknown_0203CE54->unk829[pocketId] = 0;
@@ -847,9 +847,9 @@ void sub_81ABAE0(void)
sub_8122298(&gUnknown_0203CE58.scrollPosition[i], &gUnknown_0203CE58.cursorPosition[i], gUnknown_0203CE54->unk82E[i], gUnknown_0203CE54->unk829[i], 8);
}
-u8 sub_81ABB2C(u8 a)
+u8 sub_81ABB2C(u8 pocketId)
{
- return gUnknown_0203CE58.scrollPosition[a] + gUnknown_0203CE58.cursorPosition[a];
+ return gUnknown_0203CE58.scrollPosition[pocketId] + gUnknown_0203CE58.cursorPosition[pocketId];
}
void DisplayItemMessage(u8 taskId, u8 fontId, const u8 *str, void ( *callback)(u8 taskId))
@@ -1179,7 +1179,7 @@ void sub_81AC498(u8 taskId)
sub_81AC590(taskId);
else
{
- sub_80D702C(gBagPockets[gUnknown_0203CE58.pocket].itemSlots, data[1], realPos);
+ MoveItemSlotInList(gBagPockets[gUnknown_0203CE58.pocket].itemSlots, data[1], realPos);
gUnknown_0203CE54->unk81A = -1;
DestroyListMenuTask(data[0], scrollPos, cursorPos);
if (data[1] < realPos)
@@ -1231,7 +1231,7 @@ void sub_81AC644(u8 unused)
gUnknown_0203CE54->unk828 = 4;
break;
case 8:
- if (!itemid_is_unique(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY)
+ if (!ItemId_GetImportance(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY)
{
gUnknown_0203CE54->unk820 = gUnknown_0861404B;
gUnknown_0203CE54->unk828 = 2;
@@ -1243,7 +1243,7 @@ void sub_81AC644(u8 unused)
}
break;
case 6:
- if (!itemid_is_unique(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY)
+ if (!ItemId_GetImportance(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY)
{
gUnknown_0203CE54->unk820 = gUnknown_0861404D;
gUnknown_0203CE54->unk828 = 2;
@@ -1255,7 +1255,7 @@ void sub_81AC644(u8 unused)
}
break;
case 7:
- if (!itemid_is_unique(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY)
+ if (!ItemId_GetImportance(gSpecialVar_ItemId) && gSpecialVar_ItemId != ITEM_ENIGMA_BERRY)
{
gUnknown_0203CE54->unk820 = gUnknown_0861404F;
gUnknown_0203CE54->unk828 = 2;
@@ -1605,7 +1605,7 @@ void ItemMenu_Give(u8 taskId)
{
DisplayItemMessage(taskId, 1, gText_CantWriteMail, sub_81AD350);
}
- else if (!itemid_is_unique(gSpecialVar_ItemId))
+ else if (!ItemId_GetImportance(gSpecialVar_ItemId))
{
if (CalculatePlayerPartyCount() == 0)
bag_menu_print_there_is_no_pokemon(taskId);
@@ -1686,7 +1686,7 @@ void item_menu_type_2(u8 taskId)
StringExpandPlaceholders(gStringVar4, gText_Var1CantBeHeldHere);
DisplayItemMessage(taskId, 1, gStringVar4, sub_81AD350);
}
- else if (gUnknown_0203CE58.pocket != 4 && !itemid_is_unique(gSpecialVar_ItemId))
+ else if (gUnknown_0203CE58.pocket != 4 && !ItemId_GetImportance(gSpecialVar_ItemId))
{
unknown_ItemMenu_Confirm(taskId);
}
@@ -1700,7 +1700,7 @@ void item_menu_type_b(u8 taskId)
{
if (ItemIsMail(gSpecialVar_ItemId) == TRUE)
DisplayItemMessage(taskId, 1, gText_CantWriteMail, sub_81AD350);
- else if (gUnknown_0203CE58.pocket != 4 && !itemid_is_unique(gSpecialVar_ItemId))
+ else if (gUnknown_0203CE58.pocket != 4 && !ItemId_GetImportance(gSpecialVar_ItemId))
gTasks[taskId].func = unknown_ItemMenu_Confirm;
else
bag_menu_print_cant_be_held_msg(taskId);
@@ -1738,7 +1738,7 @@ void display_sell_item_ask_str(u8 taskId)
{
s16* data = gTasks[taskId].data;
- if (itemid_get_market_price(gSpecialVar_ItemId) == 0)
+ if (ItemId_GetPrice(gSpecialVar_ItemId) == 0)
{
CopyItemName(gSpecialVar_ItemId, gStringVar2);
StringExpandPlaceholders(gStringVar4, gText_CantBuyKeyItem);
@@ -1765,7 +1765,7 @@ void sub_81AD680(u8 taskId)
{
s16* data = gTasks[taskId].data;
- ConvertIntToDecimalStringN(gStringVar1, (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8], 0, 6);
+ ConvertIntToDecimalStringN(gStringVar1, (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8], 0, 6);
StringExpandPlaceholders(gStringVar4, gText_ICanPayVar1);
DisplayItemMessage(taskId, 1, gStringVar4, sub_81AD6E4);
}
@@ -1790,7 +1790,7 @@ void sub_81AD730(u8 taskId)
s16* data = gTasks[taskId].data;
u8 windowId = bag_menu_add_window(8);
- sub_81ABCC0(windowId, 1, (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8]);
+ sub_81ABCC0(windowId, 1, (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8]);
bag_menu_AddMoney_window();
gTasks[taskId].func = sub_81AD794;
}
@@ -1801,7 +1801,7 @@ void sub_81AD794(u8 taskId)
if (AdjustQuantityAccordingToDPadInput(&data[8], data[2]) == TRUE)
{
- sub_81ABCC0(gUnknown_0203CE54->unk818, data[8], (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8]);
+ sub_81ABCC0(gUnknown_0203CE54->unk818, data[8], (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8]);
}
else if (gMain.newKeys & A_BUTTON)
{
@@ -1825,7 +1825,7 @@ void sub_81AD84C(u8 taskId)
s16* data = gTasks[taskId].data;
CopyItemName(gSpecialVar_ItemId, gStringVar2);
- ConvertIntToDecimalStringN(gStringVar1, (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8], 0, 6);
+ ConvertIntToDecimalStringN(gStringVar1, (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8], 0, 6);
StringExpandPlaceholders(gStringVar4, gText_TurnedOverVar1ForVar2);
DisplayItemMessage(taskId, 1, gStringVar4, sub_81AD8C8);
}
@@ -1838,7 +1838,7 @@ void sub_81AD8C8(u8 taskId)
PlaySE(SE_REGI);
RemoveBagItem(gSpecialVar_ItemId, data[8]);
- AddMoney(&gSaveBlock1Ptr->money, (itemid_get_market_price(gSpecialVar_ItemId) / 2) * data[8]);
+ AddMoney(&gSaveBlock1Ptr->money, (ItemId_GetPrice(gSpecialVar_ItemId) / 2) * data[8]);
DestroyListMenuTask(data[0], scrollPos, cursorPos);
sub_81AB9A8(gUnknown_0203CE58.pocket);
sub_81ABA88(gUnknown_0203CE58.pocket);
@@ -1908,7 +1908,7 @@ void sub_81ADB14(u8 taskId)
s16* data = gTasks[taskId].data;
FillWindowPixelBuffer(1, 0);
- if (itemid_is_unique(gSpecialVar_ItemId))
+ if (ItemId_GetImportance(gSpecialVar_ItemId))
{
bag_menu_print(1, 1, gText_CantStoreImportantItems, 3, 1, 0, 0, 0, 0);
gTasks[taskId].func = sub_81ADC0C;
diff --git a/src/item_menu_icons.c b/src/item_menu_icons.c
index 1d9dbb106..f12bb454e 100644
--- a/src/item_menu_icons.c
+++ b/src/item_menu_icons.c
@@ -9,6 +9,9 @@
#include "berry.h"
#include "graphics.h"
#include "constants/items.h"
+#include "item.h"
+#include "item_use.h"
+#include "constants/hold_effects.h"
struct CompressedTilesPal
{
@@ -466,6 +469,9 @@ const struct SpriteTemplate gUnknown_0857FE88 =
.callback = sub_80D5B48,
};
+#include "data/text/item_descriptions.h"
+#include "data/items.h"
+
// code
void RemoveBagSprite(u8 id)
{
diff --git a/src/lilycove_lady.c b/src/lilycove_lady.c
index 812f1f975..ea244b6a0 100644
--- a/src/lilycove_lady.c
+++ b/src/lilycove_lady.c
@@ -392,7 +392,7 @@ bool8 sub_818DC60(void)
static void sub_818DCAC(u8 *dest, u16 itemId)
{
- StringCopy(dest, ItemId_GetItem(itemId)->name);
+ StringCopy(dest, ItemId_GetName(itemId));
}
void sub_818DCC8(void)
@@ -671,7 +671,7 @@ static u8 sub_818E258(const u8 *str)
void sub_818E274(void)
{
- StringCopy(gStringVar1, ItemId_GetItem(gUnknown_0203CD68->itemId)->name);
+ StringCopy(gStringVar1, ItemId_GetName(gUnknown_0203CD68->itemId));
}
bool8 sub_818E298(void)
diff --git a/src/load_save.c b/src/load_save.c
index e3de66bb8..917c1dfe1 100644
--- a/src/load_save.c
+++ b/src/load_save.c
@@ -4,33 +4,30 @@
#include "main.h"
#include "pokemon.h"
#include "random.h"
+#include "malloc.h"
+#include "item.h"
extern void* gUnknown_0203CF5C;
extern bool16 IdentifyFlash(void);
-extern void SetBagItemsPointers(void);
extern void SetDecorationInventoriesPointers(void);
extern void ApplyNewEncryptionKeyToGameStats(u32 key);
-extern void ApplyNewEncryptionKeyToBagItems(u32 newKey);
-extern void ApplyNewEncryptionKeyToBagItems_(u32 key);
extern void ApplyNewEncryptionKeyToBerryPowder(u32 key);
extern void sub_8084FAC(int unused);
-// this is probably wrong or misleading due to it being used in ResetHeap...
-extern void InitHeap(void *pointer, u32 size);
-
#define SAVEBLOCK_MOVE_RANGE 128
struct LoadedSaveData
{
- /*0x0000*/ struct ItemSlot items[30];
- /*0x0078*/ struct ItemSlot keyItems[30];
- /*0x00F0*/ struct ItemSlot pokeBalls[16];
- /*0x0130*/ struct ItemSlot TMsHMs[64];
- /*0x0230*/ struct ItemSlot berries[46];
+ /*0x0000*/ struct ItemSlot items[BAG_ITEMS_COUNT];
+ /*0x0078*/ struct ItemSlot keyItems[BAG_KEYITEMS_COUNT];
+ /*0x00F0*/ struct ItemSlot pokeBalls[BAG_POKEBALLS_COUNT];
+ /*0x0130*/ struct ItemSlot TMsHMs[BAG_TMHM_COUNT];
+ /*0x0230*/ struct ItemSlot berries[BAG_BERRIES_COUNT];
/*0x02E8*/ struct MailStruct mail[MAIL_COUNT];
};
+// EWRAM DATA
EWRAM_DATA struct SaveBlock2 gSaveblock2 = {0};
EWRAM_DATA u8 gSaveblock2_DMA[SAVEBLOCK_MOVE_RANGE] = {0};
@@ -43,8 +40,13 @@ EWRAM_DATA u8 gSaveblock3_DMA[SAVEBLOCK_MOVE_RANGE] = {0};
EWRAM_DATA struct LoadedSaveData gLoadedSaveData = {0};
EWRAM_DATA u32 gLastEncryptionKey = {0};
-void ApplyNewEncryptionKeyToAllEncryptedData(u32 encryptionKey);
+// IWRAM common
+IWRAM_DATA bool32 gFlashMemoryPresent;
+IWRAM_DATA struct SaveBlock1 *gSaveBlock1Ptr;
+IWRAM_DATA struct SaveBlock2 *gSaveBlock2Ptr;
+IWRAM_DATA struct PokemonStorage *gPokemonStoragePtr;
+// code
void CheckForFlashMemory(void)
{
if (!IdentifyFlash())
@@ -53,7 +55,9 @@ void CheckForFlashMemory(void)
InitFlashTimer();
}
else
+ {
gFlashMemoryPresent = FALSE;
+ }
}
void ClearSav2(void)
@@ -80,8 +84,6 @@ void SetSaveBlocksPointers(u16 offset)
SetDecorationInventoriesPointers();
}
-extern u8 gHeap[];
-
void MoveSaveBlocks_ResetHeap(void)
{
void *vblankCB, *hblankCB;
@@ -132,7 +134,6 @@ void MoveSaveBlocks_ResetHeap(void)
gSaveBlock2Ptr->encryptionKey = encryptionKey;
}
-
u32 GetSecretBase2Field_9(void)
{
return gSaveBlock2Ptr->specialSaveWarp & 1;
@@ -159,112 +160,112 @@ void sav2_gender2_inplace_and_xFE(void)
gSaveBlock2Ptr->specialSaveWarp &= ~1;
}
-void copy_player_party_to_sav1(void) // SavePlayerParty
+void SavePlayerParty(void)
{
int i;
gSaveBlock1Ptr->playerPartyCount = gPlayerPartyCount;
- for (i = 0; i < 6; i++)
+ for (i = 0; i < PARTY_SIZE; i++)
gSaveBlock1Ptr->playerParty[i] = gPlayerParty[i];
}
-void copy_player_party_from_sav1(void) // LoadPlayerParty
+void LoadPlayerParty(void)
{
int i;
gPlayerPartyCount = gSaveBlock1Ptr->playerPartyCount;
- for (i = 0; i < 6; i++)
+ for (i = 0; i < PARTY_SIZE; i++)
gPlayerParty[i] = gSaveBlock1Ptr->playerParty[i];
}
-void save_serialize_npcs(void) // SaveMapObjects
+void SaveMapObjects(void)
{
int i;
- for (i = 0; i < 16; i++)
+ for (i = 0; i < MAP_OBJECTS_COUNT; i++)
gSaveBlock1Ptr->mapObjects[i] = gMapObjects[i];
}
-void save_deserialize_npcs(void) // LoadMapObjects
+void LoadMapObjects(void)
{
int i;
- for (i = 0; i < 16; i++)
+ for (i = 0; i < MAP_OBJECTS_COUNT; i++)
gMapObjects[i] = gSaveBlock1Ptr->mapObjects[i];
}
void SaveSerializedGame(void)
{
- copy_player_party_to_sav1();
- save_serialize_npcs();
+ SavePlayerParty();
+ SaveMapObjects();
}
void LoadSerializedGame(void)
{
- copy_player_party_from_sav1();
- save_deserialize_npcs();
+ LoadPlayerParty();
+ LoadMapObjects();
}
-void copy_bags_and_unk_data_from_save_blocks(void)
+void LoadPlayerBag(void)
{
int i;
// load player items.
- for (i = 0; i < 30; i++)
+ for (i = 0; i < BAG_ITEMS_COUNT; i++)
gLoadedSaveData.items[i] = gSaveBlock1Ptr->bagPocket_Items[i];
// load player key items.
- for (i = 0; i < 30; i++)
+ for (i = 0; i < BAG_KEYITEMS_COUNT; i++)
gLoadedSaveData.keyItems[i] = gSaveBlock1Ptr->bagPocket_KeyItems[i];
// load player pokeballs.
- for (i = 0; i < 16; i++)
+ for (i = 0; i < BAG_POKEBALLS_COUNT; i++)
gLoadedSaveData.pokeBalls[i] = gSaveBlock1Ptr->bagPocket_PokeBalls[i];
// load player TMs and HMs.
- for (i = 0; i < 64; i++)
+ for (i = 0; i < BAG_TMHM_COUNT; i++)
gLoadedSaveData.TMsHMs[i] = gSaveBlock1Ptr->bagPocket_TMHM[i];
// load player berries.
- for (i = 0; i < 46; i++)
+ for (i = 0; i < BAG_BERRIES_COUNT; i++)
gLoadedSaveData.berries[i] = gSaveBlock1Ptr->bagPocket_Berries[i];
// load mail.
- for (i = 0; i < 16; i++)
+ for (i = 0; i < MAIL_COUNT; i++)
gLoadedSaveData.mail[i] = gSaveBlock1Ptr->mail[i];
gLastEncryptionKey = gSaveBlock2Ptr->encryptionKey;
}
-void copy_bags_and_unk_data_to_save_blocks(void)
+void SavePlayerBag(void)
{
int i;
u32 encryptionKeyBackup;
// save player items.
- for (i = 0; i < 30; i++)
+ for (i = 0; i < BAG_ITEMS_COUNT; i++)
gSaveBlock1Ptr->bagPocket_Items[i] = gLoadedSaveData.items[i];
// save player key items.
- for (i = 0; i < 30; i++)
+ for (i = 0; i < BAG_KEYITEMS_COUNT; i++)
gSaveBlock1Ptr->bagPocket_KeyItems[i] = gLoadedSaveData.keyItems[i];
// save player pokeballs.
- for (i = 0; i < 16; i++)
+ for (i = 0; i < BAG_POKEBALLS_COUNT; i++)
gSaveBlock1Ptr->bagPocket_PokeBalls[i] = gLoadedSaveData.pokeBalls[i];
// save player TMs and HMs.
- for (i = 0; i < 64; i++)
+ for (i = 0; i < BAG_TMHM_COUNT; i++)
gSaveBlock1Ptr->bagPocket_TMHM[i] = gLoadedSaveData.TMsHMs[i];
// save player berries.
- for (i = 0; i < 46; i++)
+ for (i = 0; i < BAG_BERRIES_COUNT; i++)
gSaveBlock1Ptr->bagPocket_Berries[i] = gLoadedSaveData.berries[i];
// save mail.
- for (i = 0; i < 16; i++)
+ for (i = 0; i < MAIL_COUNT; i++)
gSaveBlock1Ptr->mail[i] = gLoadedSaveData.mail[i];
encryptionKeyBackup = gSaveBlock2Ptr->encryptionKey;
diff --git a/src/mail.c b/src/mail.c
index 85ba86974..8fddc7045 100644
--- a/src/mail.c
+++ b/src/mail.c
@@ -101,7 +101,7 @@ struct MailRead
/*0x021c*/ u8 monIconSprite;
/*0x021d*/ u8 language;
/*0x021e*/ bool8 playerIsSender;
- /*0x0220*/ void (*parserSingle)(u8 *dest, u16 word);
+ /*0x0220*/ u8 * (*parserSingle)(u8 *dest, u16 word);
/*0x0224*/ void (*parserMultiple)(u8 *dest, const u16 *src, u16 length1, u16 length2);
/*0x0228*/ const struct MailLayout *layout;
/*0x022c*/ u8 bg1TilemapBuffer[0x1000];
diff --git a/src/mauville_old_man.c b/src/mauville_old_man.c
new file mode 100644
index 000000000..ea466b2ec
--- /dev/null
+++ b/src/mauville_old_man.c
@@ -0,0 +1,1247 @@
+#include "global.h"
+#include "main.h"
+#include "constants/songs.h"
+#include "constants/easy_chat.h"
+#include "constants/map_objects.h"
+#include "constants/vars.h"
+#include "mauville_old_man.h"
+#include "event_data.h"
+#include "string_util.h"
+#include "text.h"
+#include "easy_chat.h"
+#include "script.h"
+#include "random.h"
+#include "event_scripts.h"
+#include "task.h"
+#include "menu.h"
+#include "m4a.h"
+#include "bard_music.h"
+#include "sound.h"
+#include "strings.h"
+#include "overworld.h"
+#include "field_message_box.h"
+#include "script_menu.h"
+#include "trader.h"
+
+#define CHAR_SONG_WORD_SEPARATOR 0x37
+
+extern struct MusicPlayerInfo gMPlayInfo_SE2;
+
+static void InitGiddyTaleList(void);
+static void StartBardSong(bool8 useTemporaryLyrics);
+static void Task_BardSong(u8 taskId);
+static void StorytellerSetup(void);
+static void Storyteller_ResetFlag(void);
+
+IWRAM_DATA u8 sSelectedStory;
+
+struct BardSong gBardSong;
+
+static EWRAM_DATA u16 sUnknownBardRelated = 0;
+static EWRAM_DATA struct MauvilleManStoryteller * sStorytellerPtr = NULL;
+static EWRAM_DATA u8 sStorytellerWindowId = 0;
+
+static const u16 sDefaultBardSongLyrics[6] = {
+ EC_WORD_SHAKE,
+ EC_WORD_IT,
+ EC_WORD_DO,
+ EC_WORD_THE,
+ EC_WORD_DIET,
+ EC_WORD_DANCE
+};
+
+static const u8 * const sGiddyAdjectives[] = {
+ gText_SoPretty,
+ gText_SoDarling,
+ gText_SoRelaxed,
+ gText_SoSunny,
+ gText_SoDesirable,
+ gText_SoExciting,
+ gText_SoAmusing,
+ gText_SoMagical
+};
+
+static const u8 * const sGiddyQuestions[] = {
+ gUnknown_08294313,
+ gUnknown_08294359,
+ gUnknown_08294398,
+ gUnknown_082943DA,
+ gUnknown_0829441C,
+ gUnknown_08294460,
+ gUnknown_082944A0,
+ gUnknown_082944D5
+};
+
+static void SetupBard(void)
+{
+ u16 i;
+ struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
+
+ bard->id = MAUVILLE_MAN_BARD;
+ bard->hasChangedSong = FALSE;
+ bard->language = gGameLanguage;
+ for (i = 0; i < 6; i++)
+ bard->songLyrics[i] = sDefaultBardSongLyrics[i];
+}
+
+static void SetupHipster(void)
+{
+ struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster;
+
+ hipster->id = MAUVILLE_MAN_HIPSTER;
+ hipster->alreadySpoken = FALSE;
+ hipster->language = gGameLanguage;
+}
+
+static void SetupStoryteller(void)
+{
+ StorytellerSetup();
+}
+
+static void SetupGiddy(void)
+{
+ struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy;
+
+ giddy->id = MAUVILLE_MAN_GIDDY;
+ giddy->taleCounter = 0;
+ giddy->language = gGameLanguage;
+}
+
+static void SetupTrader(void)
+{
+ TraderSetup();
+}
+
+void SetMauvilleOldMan(void)
+{
+ u16 trainerId = (gSaveBlock2Ptr->playerTrainerId[1] << 8) | gSaveBlock2Ptr->playerTrainerId[0];
+
+
+ // Determine man based on the last digit of the player's trainer ID.
+ switch ((trainerId % 10) / 2)
+ {
+ case MAUVILLE_MAN_BARD:
+ SetupBard();
+ break;
+ case MAUVILLE_MAN_HIPSTER:
+ SetupHipster();
+ break;
+ case MAUVILLE_MAN_TRADER:
+ SetupTrader();
+ break;
+ case MAUVILLE_MAN_STORYTELLER:
+ SetupStoryteller();
+ break;
+ case MAUVILLE_MAN_GIDDY:
+ SetupGiddy();
+ break;
+ }
+ ScrSpecial_SetMauvilleOldManMapObjGfx();
+}
+
+u8 GetCurrentMauvilleOldMan(void)
+{
+ struct MauvilleManCommon *common = &gSaveBlock1Ptr->oldMan.common;
+
+ return common->id;
+}
+
+void ScrSpecial_GetCurrentMauvilleMan(void)
+{
+ gSpecialVar_Result = GetCurrentMauvilleOldMan();
+}
+
+void ScrSpecial_HasBardSongBeenChanged(void)
+{
+ u16 *scriptResult = &gSpecialVar_Result; // why??
+ struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
+
+ *scriptResult = bard->hasChangedSong;
+}
+
+void ScrSpecial_SaveBardSongLyrics(void)
+{
+ u16 i;
+ struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
+
+ StringCopy(bard->playerName, gSaveBlock2Ptr->playerName);
+
+ for (i = 0; i < 4; i++)
+ bard->playerTrainerId[i] = gSaveBlock2Ptr->playerTrainerId[i];
+
+ for (i = 0; i < 6; i++)
+ bard->songLyrics[i] = bard->temporaryLyrics[i];
+
+ bard->hasChangedSong = TRUE;
+}
+
+// Copies lyrics into gStringVar4
+static void PrepareSongText(void)
+{
+ struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
+ u16 * lyrics = gSpecialVar_0x8004 == 0 ? bard->songLyrics : bard->temporaryLyrics;
+ u8 * wordEnd = gStringVar4;
+ u8 * str = wordEnd;
+ u16 lineNum;
+
+ // Put three words on each line
+ for (lineNum = 0; lineNum < 2; lineNum++)
+ {
+ wordEnd = CopyEasyChatWord(wordEnd, *(lyrics++));
+ while (wordEnd != str)
+ {
+ if (*str == CHAR_SPACE)
+ *str = CHAR_SONG_WORD_SEPARATOR;
+ str++;
+ }
+
+ str++;
+ *(wordEnd++) = CHAR_SPACE;
+
+ wordEnd = CopyEasyChatWord(wordEnd, *(lyrics++));
+ while (wordEnd != str)
+ {
+ if (*str == CHAR_SPACE)
+ *str = CHAR_SONG_WORD_SEPARATOR;
+ str++;
+ }
+
+ str++;
+ *(wordEnd++) = CHAR_NEWLINE;
+
+ wordEnd = CopyEasyChatWord(wordEnd, *(lyrics++));
+ while (wordEnd != str)
+ {
+ if (*str == CHAR_SPACE)
+ *str = CHAR_SONG_WORD_SEPARATOR;
+ str++;
+ }
+
+ if (lineNum == 0)
+ {
+ *(wordEnd++) = EXT_CTRL_CODE_BEGIN;
+ *(wordEnd++) = 15;
+ }
+ }
+}
+
+void ScrSpecial_PlayBardSong(void)
+{
+ StartBardSong(gSpecialVar_0x8004);
+ ScriptContext1_Stop();
+}
+
+void ScrSpecial_GetHipsterSpokenFlag(void)
+{
+ u16 *scriptResult = &gSpecialVar_Result; // again??
+ struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster;
+
+ *scriptResult = hipster->alreadySpoken;
+}
+
+void ScrSpecial_SetHipsterSpokenFlag(void)
+{
+ struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster;
+
+ hipster->alreadySpoken = TRUE;
+}
+
+void ScrSpecial_HipsterTeachWord(void)
+{
+ u16 var = sub_811F01C();
+
+ if (var == 0xFFFF)
+ {
+ gSpecialVar_Result = FALSE;
+ }
+ else
+ {
+ CopyEasyChatWord(gStringVar1, var);
+ gSpecialVar_Result = TRUE;
+ }
+}
+
+void ScrSpecial_GiddyShouldTellAnotherTale(void)
+{
+ struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy;
+
+ if (giddy->taleCounter == 10)
+ {
+ gSpecialVar_Result = FALSE;
+ giddy->taleCounter = 0;
+ }
+ else
+ {
+ gSpecialVar_Result = TRUE;
+ }
+}
+
+void ScrSpecial_GenerateGiddyLine(void)
+{
+ struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy;
+
+ if (giddy->taleCounter == 0)
+ InitGiddyTaleList();
+
+ if (giddy->randomWords[giddy->taleCounter] != 0xFFFF) // is not the last element of the array?
+ {
+ u8 *stringPtr;
+ u32 adjective = Random();
+
+ adjective %= 8;
+ stringPtr = CopyEasyChatWord(gStringVar4, giddy->randomWords[giddy->taleCounter]);
+ stringPtr = StringCopy(stringPtr, gOtherText_Is);
+ stringPtr = StringCopy(stringPtr, sGiddyAdjectives[adjective]);
+ StringCopy(stringPtr, gOtherText_DontYouAgree);
+ }
+ else
+ {
+ StringCopy(gStringVar4, sGiddyQuestions[giddy->questionList[giddy->questionNum++]]);
+ }
+
+ if (!(Random() % 10))
+ giddy->taleCounter = 10;
+ else
+ giddy->taleCounter++;
+
+ gSpecialVar_Result = TRUE;
+}
+
+static void InitGiddyTaleList(void)
+{
+ struct MauvilleManGiddy *giddy = &gSaveBlock1Ptr->oldMan.giddy;
+ u16 arr[][2] = {
+ {EC_GROUP_POKEMON, 0},
+ {EC_GROUP_LIFESTYLE, 0},
+ {EC_GROUP_HOBBIES, 0},
+ {EC_GROUP_MOVE_1, 0},
+ {EC_GROUP_MOVE_2, 0},
+ {EC_GROUP_POKEMON_2, 0}
+ };
+ u16 i;
+ u16 r10;
+ u16 r7;
+ u16 r1;
+
+ for (i = 0; i < 8; i++)
+ giddy->questionList[i] = i;
+
+ for (i = 0; i < 8; i++)
+ {
+ r1 = Random() % (i + 1);
+ r7 = giddy->questionList[i];
+ giddy->questionList[i] = giddy->questionList[r1];
+ giddy->questionList[r1] = r7;
+ }
+
+ r10 = 0;
+ for (i = 0; i < 6; i++)
+ {
+ arr[i][1] = EasyChat_GetNumWordsInGroup(arr[i][0]);
+ r10 += arr[i][1];
+ }
+
+ giddy->questionNum = 0;
+ r7 = 0;
+ for (i = 0; i < 10; i++)
+ {
+ r1 = Random() % 10;
+ if (r1 < 3 && r7 < 8)
+ {
+ giddy->randomWords[i] = 0xFFFF;
+ r7++;
+ }
+ else
+ {
+ s16 r2 = Random() % r10;
+ for (r1 = 0; i < 6; r1++)
+ if ((r2 -= arr[r1][1]) <= 0)
+ break;
+ if (r1 == 6)
+ r1 = 0;
+ giddy->randomWords[i] = sub_811EE90(arr[r1][0]);
+ }
+ }
+}
+static void ResetBardFlag(void)
+{
+ struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
+
+ bard->hasChangedSong = FALSE;
+}
+
+static void ResetHipsterFlag(void)
+{
+ struct MauvilleManHipster *hipster = &gSaveBlock1Ptr->oldMan.hipster;
+
+ hipster->alreadySpoken = FALSE;
+}
+
+static void ResetTraderFlag(void)
+{
+ Trader_ResetFlag();
+}
+
+static void ResetStorytellerFlag(void)
+{
+ Storyteller_ResetFlag();
+}
+
+void ResetMauvilleOldManFlag(void) // ResetMauvilleOldManFlag
+{
+ switch (GetCurrentMauvilleOldMan())
+ {
+ case MAUVILLE_MAN_BARD:
+ ResetBardFlag();
+ break;
+ case MAUVILLE_MAN_HIPSTER:
+ ResetHipsterFlag();
+ break;
+ case MAUVILLE_MAN_STORYTELLER:
+ ResetStorytellerFlag();
+ break;
+ case MAUVILLE_MAN_TRADER:
+ ResetTraderFlag();
+ break;
+ case MAUVILLE_MAN_GIDDY:
+ break;
+ }
+ ScrSpecial_SetMauvilleOldManMapObjGfx();
+}
+
+
+#define tState data[0]
+#define tCharIndex data[3]
+#define tCurrWord data[4]
+#define tUseTemporaryLyrics data[5]
+
+#define MACRO1(a) (((a) & 3) + (((a) / 8) & 1))
+#define MACRO2(a) (((a) % 4) + (((a) / 8) & 1))
+
+static void StartBardSong(bool8 useTemporaryLyrics)
+{
+ u8 taskId = CreateTask(Task_BardSong, 80);
+
+ gTasks[taskId].tUseTemporaryLyrics = useTemporaryLyrics;
+}
+
+static void sub_81206F0(void)
+{
+ gUnknown_03002F84 = FALSE;
+}
+
+static void BardSong_TextSubPrinter(struct TextSubPrinter * printer, u16 a1)
+{
+ gUnknown_03002F84 = TRUE;
+}
+
+static void sub_8120708(const u8 * src)
+{
+ NewMenuHelpers_DrawDialogueFrame(0, 0);
+ PrintTextOnWindow(0, 1, src, 0, 1, 1, BardSong_TextSubPrinter);
+ gUnknown_03002F84 = TRUE;
+ CopyWindowToVram(0, 3);
+}
+
+static void BardSing(struct Task *task, struct BardSong *song)
+{
+ switch (task->tState)
+ {
+ case 0: // Initialize song
+ {
+ struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
+ u16 *lyrics;
+ s32 i;
+
+ // Copy lyrics
+ if (gSpecialVar_0x8004 == 0)
+ lyrics = bard->songLyrics;
+ else
+ lyrics = bard->temporaryLyrics;
+ for (i = 0; i < 6; i++)
+ song->lyrics[i] = lyrics[i];
+ song->currWord = 0;
+ }
+ break;
+ case 1: // Wait for BGM to end
+ break;
+ case 2: // Initialize word
+ {
+ u16 word = song->lyrics[song->currWord];
+ song->sound = GetWordSounds(word);
+ GetWordPhonemes(song, MACRO1(word));
+ song->currWord++;
+ if (song->sound->var00 != 0xFF)
+ song->state = 0;
+ else
+ {
+ song->state = 3;
+ song->phonemeTimer = 2;
+ }
+ break;
+ }
+ case 3:
+ case 4:
+ {
+ const struct BardSound *sound = &song->sound[song->currPhoneme];
+
+ switch (song->state)
+ {
+ case 0:
+ song->phonemeTimer = song->phonemes[song->currPhoneme].length;
+ if (sound->var00 <= 50)
+ {
+ u8 num = sound->var00 / 3;
+ m4aSongNumStart(PH_TRAP_HELD + 3 * num);
+ }
+ song->state = 2;
+ song->phonemeTimer--;
+ break;
+ case 2:
+ song->state = 1;
+ if (sound->var00 <= 50)
+ {
+ song->volume = 0x100 + sound->volume * 16;
+ m4aMPlayVolumeControl(&gMPlayInfo_SE2, 0xFFFF, song->volume);
+ song->pitch = 0x200 + song->phonemes[song->currPhoneme].pitch;
+ m4aMPlayPitchControl(&gMPlayInfo_SE2, 0xFFFF, song->pitch);
+ }
+ break;
+ case 1:
+ if (song->voiceInflection > 10)
+ song->volume -= 2;
+ if (song->voiceInflection & 1)
+ song->pitch += 64;
+ else
+ song->pitch -= 64;
+ m4aMPlayVolumeControl(&gMPlayInfo_SE2, 0xFFFF, song->volume);
+ m4aMPlayPitchControl(&gMPlayInfo_SE2, 0xFFFF, song->pitch);
+ song->voiceInflection++;
+ song->phonemeTimer--;
+ if (song->phonemeTimer == 0)
+ {
+ song->currPhoneme++;
+ if (song->currPhoneme != 6 && song->sound[song->currPhoneme].var00 != 0xFF)
+ song->state = 0;
+ else
+ {
+ song->state = 3;
+ song->phonemeTimer = 2;
+ }
+ }
+ break;
+ case 3:
+ song->phonemeTimer--;
+ if (song->phonemeTimer == 0)
+ {
+ m4aMPlayStop(&gMPlayInfo_SE2);
+ song->state = 4;
+ }
+ break;
+ }
+ }
+ break;
+ case 5:
+ break;
+ }
+}
+
+static void Task_BardSong(u8 taskId)
+{
+ struct Task *task = &gTasks[taskId]; // r5
+
+ BardSing(task, &gBardSong);
+ switch (task->tState)
+ {
+ case 0: // Initialize song
+ PrepareSongText();
+ sub_8120708(gStringVar4);
+ task->data[1] = 0;
+ task->data[2] = 0;
+ task->tCharIndex = 0;
+ task->tCurrWord = 0;
+ FadeOutBGMTemporarily(4);
+ task->tState = 1;
+ break;
+ case 1: // Wait for BGM to end
+ if (IsBGMPausedOrStopped())
+ task->tState = 2;
+ break;
+ case 2: // Initialize word
+ {
+ struct MauvilleManBard *bard = &gSaveBlock1Ptr->oldMan.bard;
+ u8 *str = gStringVar4 + task->tCharIndex;
+ u16 wordLen = 0;
+ // Can't get it to match without hacking
+ u32 temp;
+ register s16 zero asm("r1");
+
+ while (*str != CHAR_SPACE
+ && *str != CHAR_NEWLINE
+ && *str != EXT_CTRL_CODE_BEGIN
+ && *str != EOS)
+ {
+ str++;
+ wordLen++;
+ }
+ if (!task->tUseTemporaryLyrics)
+ sUnknownBardRelated = MACRO2(bard->songLyrics[task->tCurrWord]);
+ else
+ sUnknownBardRelated = MACRO2(bard->temporaryLyrics[task->tCurrWord]);
+ temp = gBardSong.length / wordLen;
+ zero = 0;
+ gBardSong.length = temp;
+ if (gBardSong.length <= 0)
+ gBardSong.length = 1;
+ task->tCurrWord++;
+ if (task->data[2] == 0)
+ task->tState = 3;
+ else
+ task->tState = 5;
+ task->data[1] = zero;
+ }
+ break;
+ case 5:
+ if (task->data[2] == 0)
+ task->tState = 3;
+ else
+ task->data[2]--;
+ break;
+ case 3:
+ if (gStringVar4[task->tCharIndex] == EOS)
+ {
+ FadeInBGM(6);
+ m4aMPlayFadeOutTemporarily(&gMPlayInfo_SE2, 2);
+ EnableBothScriptContexts();
+ DestroyTask(taskId);
+ }
+ else if (gStringVar4[task->tCharIndex] == CHAR_SPACE)
+ {
+
+ sub_81206F0();
+ task->tCharIndex++;
+ task->tState = 2;
+ task->data[2] = 0;
+ }
+ else if (gStringVar4[task->tCharIndex] == CHAR_NEWLINE)
+ {
+ task->tCharIndex++;
+ task->tState = 2;
+ task->data[2] = 0;
+ }
+ else if (gStringVar4[task->tCharIndex] == EXT_CTRL_CODE_BEGIN)
+ {
+ task->tCharIndex += 2; // skip over control codes
+ task->tState = 2;
+ task->data[2] = 8;
+ }
+ else if (gStringVar4[task->tCharIndex] == CHAR_SONG_WORD_SEPARATOR)
+ {
+ gStringVar4[task->tCharIndex] = CHAR_SPACE; // restore it back to a space
+ sub_81206F0();
+ task->tCharIndex++;
+ task->data[2] = 0;
+ }
+ else
+ {
+ switch (task->data[1])
+ {
+ case 0:
+ sub_81206F0();
+ task->data[1]++;
+ break;
+ case 1:
+ task->data[1]++;
+ break;
+ case 2:
+ task->tCharIndex++;
+ task->data[1] = 0;
+ task->data[2] = gBardSong.length;
+ task->tState = 4;
+ break;
+ }
+ }
+ break;
+ case 4:
+ task->data[2]--;
+ if (task->data[2] == 0)
+ task->tState = 3;
+ break;
+ }
+ sub_8197224();
+}
+
+void ScrSpecial_SetMauvilleOldManMapObjGfx(void)
+{
+ VarSet(VAR_0x4010, MAP_OBJ_GFX_BARD);
+}
+
+// Language fixers?
+
+void sub_8120B70(union OldMan * oldMan)
+{
+ s32 i;
+ u8 sp00[8];
+
+ switch (oldMan->common.id)
+ {
+ case MAUVILLE_MAN_TRADER:
+ {
+ struct MauvilleOldManTrader * trader = &oldMan->trader;
+ for (i = 0; i < 4; i++)
+ {
+ if (trader->language[i] == LANGUAGE_JAPANESE)
+ {
+ ConvertInternationalString(trader->playerNames[i], LANGUAGE_JAPANESE);
+ }
+ }
+ }
+ break;
+ case MAUVILLE_MAN_STORYTELLER:
+ {
+ struct MauvilleManStoryteller * storyteller = &oldMan->storyteller;
+ for (i = 0; i < 4; i++)
+ {
+ if (storyteller->gameStatIDs[i] != 0)
+ {
+ memcpy(sp00, storyteller->trainerNames[i], 7);
+ sp00[7] = EOS;
+ if (IsStringJapanese(sp00))
+ {
+ memset(sp00, CHAR_SPACE, 8);
+ StringCopy(sp00, gText_Friend);
+ memcpy(storyteller->trainerNames[i], sp00, 7);
+ storyteller->language[i] = GAME_LANGUAGE;
+ }
+ }
+ }
+ }
+ break;
+ }
+}
+
+void sub_8120C0C(union OldMan * oldMan, u32 r8, u32 r7, u32 r3)
+{
+ s32 i;
+
+ switch (oldMan->common.id)
+ {
+ case MAUVILLE_MAN_TRADER:
+ {
+ struct MauvilleOldManTrader * trader = &oldMan->trader;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (IsStringJapanese(trader->playerNames[i]))
+ {
+ trader->language[i] = r8;
+ }
+ else
+ {
+ trader->language[i] = r7;
+ }
+ }
+ }
+ break;
+ case MAUVILLE_MAN_STORYTELLER:
+ {
+ struct MauvilleManStoryteller * storyteller = &oldMan->storyteller;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (IsStringJapanese(storyteller->trainerNames[i]))
+ {
+ storyteller->language[i] = r8;
+ }
+ else
+ {
+ storyteller->language[i] = r7;
+ }
+ }
+ }
+ break;
+ case MAUVILLE_MAN_BARD:
+ {
+ struct MauvilleManBard * bard = &oldMan->bard;
+
+ if (r3 == LANGUAGE_JAPANESE)
+ bard->language = r8;
+ else
+ bard->language = r7;
+ }
+ break;
+ case MAUVILLE_MAN_HIPSTER:
+ {
+ struct MauvilleManHipster * hipster = &oldMan->hipster;
+
+ if (r3 == LANGUAGE_JAPANESE)
+ hipster->language = r8;
+ else
+ hipster->language = r7;
+ }
+ break;
+ case MAUVILLE_MAN_GIDDY:
+ {
+ struct MauvilleManGiddy * giddy = &oldMan->giddy;
+
+ if (r3 == LANGUAGE_JAPANESE)
+ giddy->language = r8;
+ else
+ giddy->language = r7;
+ }
+ break;
+ }
+}
+
+void sub_8120CD0(union OldMan * oldMan, u32 unused, u32 a2)
+{
+ u8 sp00[8];
+ s32 i;
+ if (oldMan->common.id == MAUVILLE_MAN_STORYTELLER && a2 == LANGUAGE_JAPANESE)
+ {
+ struct MauvilleManStoryteller * storyteller = &oldMan->storyteller;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (storyteller->gameStatIDs[i] != 0)
+ {
+ memcpy(sp00, storyteller->trainerNames[i], 7);
+ sp00[7] = EOS;
+ if (IsStringJapanese(sp00))
+ storyteller->language[i] = LANGUAGE_JAPANESE;
+ else
+ storyteller->language[i] = GAME_LANGUAGE;
+ }
+ }
+ }
+}
+
+void sub_8120D34(union OldMan * oldMan, u32 r1, u32 r6)
+{
+ u32 r2 = (r1 == LANGUAGE_JAPANESE || r1 == LANGUAGE_ENGLISH) ? 1 : 0;
+ switch (oldMan->common.id)
+ {
+ case MAUVILLE_MAN_TRADER:
+ {
+ struct MauvilleOldManTrader * trader = &oldMan->trader;
+ s32 i;
+
+ if (r2)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ u8 * str = trader->playerNames[i];
+ if (str[0] == EXT_CTRL_CODE_BEGIN && str[1] == EXT_CTRL_CODE_JPN)
+ {
+ StripExtCtrlCodes(str);
+ trader->language[i] = LANGUAGE_JAPANESE;
+ }
+ else
+ trader->language[i] = r6;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 4; i++)
+ {
+ if (trader->language[i] == LANGUAGE_JAPANESE)
+ {
+ StripExtCtrlCodes(trader->playerNames[i]);
+ }
+ }
+ }
+ }
+ break;
+ case MAUVILLE_MAN_STORYTELLER:
+ {
+
+ struct MauvilleManStoryteller * storyteller = &oldMan->storyteller;
+ s32 i;
+
+ if (r2)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ if (storyteller->gameStatIDs[i] != 0)
+ storyteller->language[i] = r6;
+ }
+ }
+ }
+ break;
+ case MAUVILLE_MAN_BARD:
+ {
+ struct MauvilleManBard * bard = &oldMan->bard;
+
+ if (r2)
+ {
+ bard->language = r6;
+ }
+ }
+ break;
+ case MAUVILLE_MAN_HIPSTER:
+ {
+ struct MauvilleManHipster * hipster = &oldMan->hipster;
+
+ if (r2)
+ {
+ hipster->language = r6;
+ }
+ }
+ break;
+ case MAUVILLE_MAN_GIDDY:
+ {
+ struct MauvilleManGiddy * giddy = &oldMan->giddy;
+
+ if (r2)
+ {
+ giddy->language = r6;
+ }
+ }
+ break;
+ }
+}
+
+struct Story
+{
+ u8 stat;
+ u8 minVal;
+ const u8 *title;
+ const u8 *action;
+ const u8 *fullText;
+};
+
+static const struct Story sStorytellerStories[] = {
+ {GAME_STAT_50, 1, MauvilleCity_PokemonCenter_1F_Text_28E930, MauvilleCity_PokemonCenter_1F_Text_28E947, MauvilleCity_PokemonCenter_1F_Text_28E956},
+ {GAME_STAT_STARTED_TRENDS, 1, MauvilleCity_PokemonCenter_1F_Text_28E9D7, MauvilleCity_PokemonCenter_1F_Text_28E9EF, MauvilleCity_PokemonCenter_1F_Text_28E9FE},
+ {GAME_STAT_PLANTED_BERRIES, 1, MauvilleCity_PokemonCenter_1F_Text_28EA7D, MauvilleCity_PokemonCenter_1F_Text_28EA98, MauvilleCity_PokemonCenter_1F_Text_28EAA8},
+ {GAME_STAT_TRADED_BIKES, 1, MauvilleCity_PokemonCenter_1F_Text_28EB19, MauvilleCity_PokemonCenter_1F_Text_28EB31, MauvilleCity_PokemonCenter_1F_Text_28EB3E},
+ {GAME_STAT_GOT_INTERVIEWED, 1, MauvilleCity_PokemonCenter_1F_Text_28EBB5, MauvilleCity_PokemonCenter_1F_Text_28EBCD, MauvilleCity_PokemonCenter_1F_Text_28EBDD},
+ {GAME_STAT_TRAINER_BATTLES, 1, MauvilleCity_PokemonCenter_1F_Text_28EC60, MauvilleCity_PokemonCenter_1F_Text_28EC79, MauvilleCity_PokemonCenter_1F_Text_28EC81},
+ {GAME_STAT_POKEMON_CAPTURES, 1, MauvilleCity_PokemonCenter_1F_Text_28ED04, MauvilleCity_PokemonCenter_1F_Text_28ED21, MauvilleCity_PokemonCenter_1F_Text_28ED30},
+ {GAME_STAT_FISHING_CAPTURES, 1, MauvilleCity_PokemonCenter_1F_Text_28EDA1, MauvilleCity_PokemonCenter_1F_Text_28EDB5, MauvilleCity_PokemonCenter_1F_Text_28EDCF},
+ {GAME_STAT_HATCHED_EGGS, 1, MauvilleCity_PokemonCenter_1F_Text_28EE45, MauvilleCity_PokemonCenter_1F_Text_28EE5D, MauvilleCity_PokemonCenter_1F_Text_28EE6A},
+ {GAME_STAT_EVOLVED_POKEMON, 1, MauvilleCity_PokemonCenter_1F_Text_28EEDD, MauvilleCity_PokemonCenter_1F_Text_28EEF1, MauvilleCity_PokemonCenter_1F_Text_28EF01},
+ {GAME_STAT_USED_POKECENTER, 1, MauvilleCity_PokemonCenter_1F_Text_28EF73, MauvilleCity_PokemonCenter_1F_Text_28EF95, MauvilleCity_PokemonCenter_1F_Text_28EFAA},
+ {GAME_STAT_RESTED_AT_HOME, 1, MauvilleCity_PokemonCenter_1F_Text_28F045, MauvilleCity_PokemonCenter_1F_Text_28F05A, MauvilleCity_PokemonCenter_1F_Text_28F071},
+ {GAME_STAT_ENTERED_SAFARI_ZONE, 1, MauvilleCity_PokemonCenter_1F_Text_28F0F3, MauvilleCity_PokemonCenter_1F_Text_28F10D, MauvilleCity_PokemonCenter_1F_Text_28F125},
+ {GAME_STAT_USED_CUT, 1, MauvilleCity_PokemonCenter_1F_Text_28F1BE, MauvilleCity_PokemonCenter_1F_Text_28F1D5, MauvilleCity_PokemonCenter_1F_Text_28F1DE},
+ {GAME_STAT_USED_ROCK_SMASH, 1, MauvilleCity_PokemonCenter_1F_Text_28F24F, MauvilleCity_PokemonCenter_1F_Text_28F269, MauvilleCity_PokemonCenter_1F_Text_28F277},
+ {GAME_STAT_MOVED_SECRET_BASE, 1, MauvilleCity_PokemonCenter_1F_Text_28F2FC, MauvilleCity_PokemonCenter_1F_Text_28F314, MauvilleCity_PokemonCenter_1F_Text_28F32A},
+ {GAME_STAT_USED_SPLASH, 1, MauvilleCity_PokemonCenter_1F_Text_28F3AD, MauvilleCity_PokemonCenter_1F_Text_28F3C6, MauvilleCity_PokemonCenter_1F_Text_28F3D2},
+ {GAME_STAT_USED_STRUGGLE, 1, MauvilleCity_PokemonCenter_1F_Text_28F44B, MauvilleCity_PokemonCenter_1F_Text_28F461, MauvilleCity_PokemonCenter_1F_Text_28F47C},
+ {GAME_STAT_SLOT_JACKPOTS, 1, MauvilleCity_PokemonCenter_1F_Text_28F50C, MauvilleCity_PokemonCenter_1F_Text_28F51B, MauvilleCity_PokemonCenter_1F_Text_28F538},
+ {GAME_STAT_CONSECUTIVE_ROULETTE_WINS, 2, MauvilleCity_PokemonCenter_1F_Text_28F5BE, MauvilleCity_PokemonCenter_1F_Text_28F5D1, MauvilleCity_PokemonCenter_1F_Text_28F5F2},
+ {GAME_STAT_ENTERED_BATTLE_TOWER, 1, MauvilleCity_PokemonCenter_1F_Text_28F678, MauvilleCity_PokemonCenter_1F_Text_28F694, MauvilleCity_PokemonCenter_1F_Text_28F6B4},
+ {GAME_STAT_POKEBLOCKS, 1, MauvilleCity_PokemonCenter_1F_Text_28F751, MauvilleCity_PokemonCenter_1F_Text_28F76A, MauvilleCity_PokemonCenter_1F_Text_28F776},
+ {GAME_STAT_ENTERED_CONTEST, 1, MauvilleCity_PokemonCenter_1F_Text_28F7F6, MauvilleCity_PokemonCenter_1F_Text_28F811, MauvilleCity_PokemonCenter_1F_Text_28F822},
+ {GAME_STAT_WON_CONTEST, 1, MauvilleCity_PokemonCenter_1F_Text_28F89C, MauvilleCity_PokemonCenter_1F_Text_28F8AF, MauvilleCity_PokemonCenter_1F_Text_28F8BC},
+ {GAME_STAT_SHOPPED, 1, MauvilleCity_PokemonCenter_1F_Text_28F92F, MauvilleCity_PokemonCenter_1F_Text_28F941, MauvilleCity_PokemonCenter_1F_Text_28F949},
+ {GAME_STAT_USED_ITEMFINDER, 1, MauvilleCity_PokemonCenter_1F_Text_28F9D1, MauvilleCity_PokemonCenter_1F_Text_28F9EA, MauvilleCity_PokemonCenter_1F_Text_28F9FD},
+ {GAME_STAT_GOT_RAINED_ON, 1, MauvilleCity_PokemonCenter_1F_Text_28FA81, MauvilleCity_PokemonCenter_1F_Text_28FA99, MauvilleCity_PokemonCenter_1F_Text_28FAA7},
+ {GAME_STAT_CHECKED_POKEDEX, 1, MauvilleCity_PokemonCenter_1F_Text_28FB1D, MauvilleCity_PokemonCenter_1F_Text_28FB35, MauvilleCity_PokemonCenter_1F_Text_28FB47},
+ {GAME_STAT_RECEIVED_RIBBONS, 1, MauvilleCity_PokemonCenter_1F_Text_28FBC4, MauvilleCity_PokemonCenter_1F_Text_28FBD9, MauvilleCity_PokemonCenter_1F_Text_28FBEA},
+ {GAME_STAT_JUMPED_DOWN_LEDGES, 1, MauvilleCity_PokemonCenter_1F_Text_28FC6B, MauvilleCity_PokemonCenter_1F_Text_28FC85, MauvilleCity_PokemonCenter_1F_Text_28FC98},
+ {GAME_STAT_WATCHED_TV, 1, MauvilleCity_PokemonCenter_1F_Text_28FD1D, MauvilleCity_PokemonCenter_1F_Text_28FD35, MauvilleCity_PokemonCenter_1F_Text_28FD40},
+ {GAME_STAT_CHECKED_CLOCK, 1, MauvilleCity_PokemonCenter_1F_Text_28FDA2, MauvilleCity_PokemonCenter_1F_Text_28FDBD, MauvilleCity_PokemonCenter_1F_Text_28FDCE},
+ {GAME_STAT_WON_POKEMON_LOTTERY, 1, MauvilleCity_PokemonCenter_1F_Text_28FE57, MauvilleCity_PokemonCenter_1F_Text_28FE72, MauvilleCity_PokemonCenter_1F_Text_28FE88},
+ {GAME_STAT_USED_DAYCARE, 1, MauvilleCity_PokemonCenter_1F_Text_28FF0C, MauvilleCity_PokemonCenter_1F_Text_28FF27, MauvilleCity_PokemonCenter_1F_Text_28FF44},
+ {GAME_STAT_RODE_CABLE_CAR, 1, MauvilleCity_PokemonCenter_1F_Text_28FFDD, MauvilleCity_PokemonCenter_1F_Text_28FFFA, MauvilleCity_PokemonCenter_1F_Text_29000D},
+ {GAME_STAT_ENTERED_HOT_SPRINGS, 1, MauvilleCity_PokemonCenter_1F_Text_290097, MauvilleCity_PokemonCenter_1F_Text_2900B5, MauvilleCity_PokemonCenter_1F_Text_2900CB}
+};
+
+static void StorytellerSetup(void)
+{
+ s32 i;
+ sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
+
+ sStorytellerPtr->id = MAUVILLE_MAN_STORYTELLER;
+ sStorytellerPtr->alreadyRecorded = FALSE;
+ for (i = 0; i < 4; i++)
+ {
+ sStorytellerPtr->gameStatIDs[i] = 0;
+ sStorytellerPtr->trainerNames[0][i] = EOS; // Maybe they meant storyteller->trainerNames[i][0] instead?
+ }
+}
+
+static void Storyteller_ResetFlag(void)
+{
+ sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
+
+ sStorytellerPtr->id = MAUVILLE_MAN_STORYTELLER;
+ sStorytellerPtr->alreadyRecorded = FALSE;
+}
+
+static u32 StorytellerGetGameStat(u8 stat)
+{
+ if (stat == 50)
+ stat = 0;
+ return GetGameStat(stat);
+}
+
+static const struct Story *GetStoryByStat(u32 stat)
+{
+ s32 i;
+
+ for (i = 0; i < 36; i++)
+ {
+ if (sStorytellerStories[i].stat == stat)
+ return &sStorytellerStories[i];
+ }
+ return &sStorytellerStories[35];
+}
+
+static const u8 *GetStoryTitleByStat(u32 stat)
+{
+ return GetStoryByStat(stat)->title;
+}
+
+static const u8 *GetStoryTextByStat(u32 stat)
+{
+ return GetStoryByStat(stat)->fullText;
+}
+
+static const u8 *GetStoryActionByStat(u32 stat)
+{
+ return GetStoryByStat(stat)->action;
+}
+
+static u8 GetFreeStorySlot(void)
+{
+ u8 i;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (sStorytellerPtr->gameStatIDs[i] == 0)
+ break;
+ }
+ return i;
+}
+
+static u32 StorytellerGetRecordedTrainerStat(u32 trainer)
+{
+ u8 *ptr = sStorytellerPtr->statValues[trainer];
+
+ return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
+}
+
+static void StorytellerSetRecordedTrainerStat(u32 trainer, u32 val)
+{
+ u8 *ptr = sStorytellerPtr->statValues[trainer];
+
+ ptr[0] = val;
+ ptr[1] = val >> 8;
+ ptr[2] = val >> 16;
+ ptr[3] = val >> 24;
+}
+
+static bool32 HasTrainerStatIncreased(u32 trainer)
+{
+ if (StorytellerGetGameStat(sStorytellerPtr->gameStatIDs[trainer]) > StorytellerGetRecordedTrainerStat(trainer))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static void GetStoryByStattellerPlayerName(u32 player, void *dst)
+{
+ u8 *name = sStorytellerPtr->trainerNames[player];
+
+ memset(dst, EOS, 8);
+ memcpy(dst, name, 7);
+}
+
+static void StorytellerSetPlayerName(u32 player, const u8 * src)
+{
+ u8 * name = sStorytellerPtr->trainerNames[player];
+ memset(name, EOS, 7);
+ memcpy(name, src, 7);
+}
+
+
+static void StorytellerRecordNewStat(u32 player, u32 stat)
+{
+ sStorytellerPtr->gameStatIDs[player] = stat;
+ StorytellerSetPlayerName(player, gSaveBlock2Ptr->playerName);
+ StorytellerSetRecordedTrainerStat(player, StorytellerGetGameStat(stat));
+ ConvertIntToDecimalStringN(gStringVar1, StorytellerGetGameStat(stat), STR_CONV_MODE_LEFT_ALIGN, 10);
+ StringCopy(gStringVar2, GetStoryActionByStat(stat));
+ sStorytellerPtr->language[player] = gGameLanguage;
+}
+
+static void ScrambleStatList(u8 * arr, s32 count)
+{
+ s32 i;
+
+ for (i = 0; i < count; i++)
+ arr[i] = i;
+ for (i = 0; i < count; i++)
+ {
+ u32 a = Random() % count;
+ u32 b = Random() % count;
+ u8 temp = arr[a];
+ arr[a] = arr[b];
+ arr[b] = temp;
+ }
+}
+
+struct UnknownStruct_0859F288
+{
+ s32 length;
+ u32 unused2;
+};
+
+static const struct UnknownStruct_0859F288 sStorytellerStuff = {
+ ARRAY_COUNT(sStorytellerStories),
+ sizeof(sStorytellerStuff)
+};
+
+static bool8 StorytellerInitializeRandomStat(void)
+{
+ u8 arr[sStorytellerStuff.length];
+ s32 i;
+ s32 j;
+
+ ScrambleStatList(arr, ARRAY_COUNT(sStorytellerStories));
+ for (i = 0; i < (s32)ARRAY_COUNT(sStorytellerStories); i++)
+ {
+ u8 stat = sStorytellerStories[arr[i]].stat;
+ u8 minVal = sStorytellerStories[arr[i]].minVal;
+
+ for (j = 0; j < 4; j++)
+ {
+ if (sStorytellerPtr->gameStatIDs[j] == stat)
+ break;
+ }
+ if (j == 4 && StorytellerGetGameStat(stat) >= minVal)
+ {
+ sStorytellerPtr->alreadyRecorded = TRUE;
+ if (GetFreeStorySlot() == 4)
+ StorytellerRecordNewStat(sSelectedStory, stat);
+ else
+ StorytellerRecordNewStat(GetFreeStorySlot(), stat);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void StorytellerDisplayStory(u32 player)
+{
+ u8 stat = sStorytellerPtr->gameStatIDs[player];
+
+ ConvertIntToDecimalStringN(gStringVar1, StorytellerGetRecordedTrainerStat(player), 0, 10);
+ StringCopy(gStringVar2, GetStoryActionByStat(stat));
+ GetStoryByStattellerPlayerName(player, gStringVar3);
+ ConvertInternationalString(gStringVar3, sStorytellerPtr->language[player]);
+ ShowFieldMessage(GetStoryTextByStat(stat));
+}
+
+static void PrintStoryList(void)
+{
+ s32 i;
+ s32 width = GetStringWidth(1, gText_Exit, 0);
+ u8 tileWidth;
+ for (i = 0; i < 4; i++)
+ {
+ s32 curWidth;
+ u16 gameStatID = sStorytellerPtr->gameStatIDs[i];
+
+ if (gameStatID == 0)
+ break;
+ curWidth = GetStringWidth(1, GetStoryTitleByStat(gameStatID), 0);
+ if (curWidth > width)
+ width = curWidth;
+ }
+ sStorytellerWindowId = CreateWindowFromRect(0, 0, convert_pixel_width_to_tile_width(width), GetFreeStorySlot() * 2 + 2);
+ SetStandardWindowBorderStyle(sStorytellerWindowId, 0);
+ for (i = 0; i < 4; i++)
+ {
+ u16 gameStatID = sStorytellerPtr->gameStatIDs[i];
+ if (gameStatID == 0)
+ break;
+ PrintTextOnWindow(sStorytellerWindowId, 1, GetStoryTitleByStat(gameStatID), 8, 16 * i + 1, 0xFF, NULL);
+ }
+ PrintTextOnWindow(sStorytellerWindowId, 1, gText_Exit, 8, 16 * i + 1, 0xFF, NULL);
+ InitMenuInUpperLeftCornerPlaySoundWhenAPressed(sStorytellerWindowId, GetFreeStorySlot() + 1, 0);
+ CopyWindowToVram(sStorytellerWindowId, 3);
+}
+
+static void Task_StoryListMenu(u8 taskId) // Task_StoryListMenu
+{
+ struct Task *task = &gTasks[taskId];
+ s32 selection;
+
+ switch (task->data[0])
+ {
+ case 0:
+ PrintStoryList();
+ task->data[0]++;
+ break;
+ case 1:
+ selection = ProcessMenuInput();
+ if (selection == -2)
+ break;
+ if (selection == -1 || selection == GetFreeStorySlot())
+ {
+ gSpecialVar_Result = 0;
+ }
+ else
+ {
+ gSpecialVar_Result = 1;
+ sSelectedStory = selection;
+ }
+ sub_80E2A78(sStorytellerWindowId);
+ DestroyTask(taskId);
+ EnableBothScriptContexts();
+ break;
+ }
+}
+
+// Sets gSpecialVar_Result to TRUE if player selected a story
+void ScrSpecial_StorytellerStoryListMenu(void)
+{
+ CreateTask(Task_StoryListMenu, 80);
+}
+
+void ScrSpecial_StorytellerDisplayStory(void)
+{
+ StorytellerDisplayStory(sSelectedStory);
+}
+
+u8 ScrSpecial_StorytellerGetFreeStorySlot(void)
+{
+ sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
+ return GetFreeStorySlot();
+}
+
+// Returns TRUE if stat has increased
+bool8 ScrSpecial_StorytellerUpdateStat(void)
+{
+ u8 r4;
+ sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
+ r4 = sStorytellerPtr->gameStatIDs[sSelectedStory];
+
+ if (HasTrainerStatIncreased(sSelectedStory) == TRUE)
+ {
+ StorytellerRecordNewStat(sSelectedStory, r4);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool8 ScrSpecial_HasStorytellerAlreadyRecorded(void)
+{
+ sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
+
+ if (sStorytellerPtr->alreadyRecorded == FALSE)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+bool8 ScrSpecial_StorytellerInitializeRandomStat(void)
+{
+ sStorytellerPtr = &gSaveBlock1Ptr->oldMan.storyteller;
+ return StorytellerInitializeRandomStat();
+}
+
diff --git a/src/new_game.c b/src/new_game.c
index 89771e92b..37336016e 100644
--- a/src/new_game.c
+++ b/src/new_game.c
@@ -20,8 +20,10 @@
#include "tv.h"
#include "coins.h"
#include "text.h"
+#include "overworld.h"
+#include "mail.h"
+#include "battle_records.h"
-extern u8 gPlayerPartyCount;
extern u8 gDifferentSaveFile;
extern u16 gSaveFileStatus;
extern u8 gUnknown_030060B0;
@@ -29,19 +31,15 @@ extern u8 gUnknown_030060B0;
// TODO: replace those declarations with file headers
extern u16 GetGeneratedTrainerIdLower(void);
extern void ClearContestWinnerPicsInContestHall(void);
-extern void Overworld_SetWarpDestination(s8 mapBank, s8 mapNo, s8 warpNo, s8 xPos, s8 yPos);
extern void warp_in(void);
extern void sub_80BB358(void);
extern void ResetBagScrollPositions(void);
extern void ResetPokedex(void);
extern void sub_8084400(void);
-extern void ClearMailData(void);
extern void ResetGabbyAndTy(void);
extern void ResetSecretBases(void);
extern void ResetLinkContestBoolean(void);
-extern void ResetGameStats(void);
extern void sub_8052DA8(void);
-extern void InitLinkBattleRecords(void);
extern void ResetPokemonStorageSystem(void);
extern void ClearBag(void);
extern void NewGameInitPCItems(void);
@@ -58,7 +56,7 @@ extern void ResetContestLinkResults(void);
extern void ResetPokeJumpResults(void);
extern void SetBerryPowder(u32* powder, u32 newValue);
-extern u8 EventScript_2715DE[];
+extern const u8 EventScript_2715DE[];
void WriteUnalignedWord(u32 var, u8 *dataPtr)
{
@@ -178,7 +176,7 @@ void NewGameInitData(void)
ResetLinkContestBoolean();
ResetGameStats();
ClearAllContestWinnerPics();
- InitLinkBattleRecords();
+ ClearPlayerLinkBattleRecords();
InitSeedotSizeRecord();
InitLotadSizeRecord();
gPlayerPartyCount = 0;
diff --git a/src/overworld.c b/src/overworld.c
index 532615f27..f42f0db7f 100644
--- a/src/overworld.c
+++ b/src/overworld.c
@@ -137,7 +137,6 @@ extern void trainer_hill_map_load_related(void);
extern void sub_8087D74(void);
extern void battle_pyramid_map_load_related(u8);
extern void sub_80B00E8(u8);
-extern void UpdateTVScreensOnMap(u32, u32);
extern void sub_80E9238(u8);
extern void sub_81A3908(void);
extern void sub_81AA2F8(void);
@@ -614,12 +613,12 @@ bool32 warp_data_is_not_neg_1(struct WarpData *warp)
return TRUE;
}
-const struct MapHeader *Overworld_GetMapHeaderByGroupAndId(u16 mapGroup, u16 mapNum)
+struct MapHeader const *const Overworld_GetMapHeaderByGroupAndId(u16 mapGroup, u16 mapNum)
{
return gMapGroups[mapGroup][mapNum];
}
-const struct MapHeader *warp1_get_mapheader(void)
+struct MapHeader const *const warp1_get_mapheader(void)
{
return Overworld_GetMapHeaderByGroupAndId(sWarpDestination.mapGroup, sWarpDestination.mapNum);
}
diff --git a/src/player_pc.c b/src/player_pc.c
index f56ecb128..6f39fa449 100644
--- a/src/player_pc.c
+++ b/src/player_pc.c
@@ -444,7 +444,7 @@ static void ItemStorage_Withdraw(u8 taskId)
{
s16 *data = gTasks[taskId].data;
- NUM_ITEMS = sub_80D6CE4();
+ NUM_ITEMS = CountUsedPCItemSlots();
if (NUM_ITEMS != 0)
ItemStorage_WithdrawToss_Helper(taskId, FALSE);
else
@@ -459,7 +459,7 @@ static void ItemStorage_Toss(u8 taskId)
{
s16 *data = gTasks[taskId].data;
- NUM_ITEMS = sub_80D6CE4();
+ NUM_ITEMS = CountUsedPCItemSlots();
if (NUM_ITEMS != 0)
ItemStorage_WithdrawToss_Helper(taskId, TRUE);
else
@@ -967,7 +967,7 @@ static void sub_816C0C8(void)
static void sub_816C110(void)
{
- sub_80D6E84();
+ CompactPCItems();
sub_812220C(gSaveBlock1Ptr->pcItems, 50, &(playerPCItemPageInfo.pageItems), &(playerPCItemPageInfo.count), 0x8);
}
@@ -1180,7 +1180,7 @@ static void ItemStorage_DoItemSwap(u8 taskId, bool8 a)
{
if(c != b - 1)
{
- sub_80D702C(gSaveBlock1Ptr->pcItems, c, b);
+ MoveItemSlotInList(gSaveBlock1Ptr->pcItems, c, b);
ItemStorage_RefreshListMenu();
}
}
@@ -1301,7 +1301,7 @@ static void ItemStorage_DoItemToss(u8 taskId)
data = gTasks[taskId].data;
b = (playerPCItemPageInfo.cursorPos + playerPCItemPageInfo.itemsAbove);
- if(!itemid_is_unique(gSaveBlock1Ptr->pcItems[b].itemId))
+ if(!ItemId_GetImportance(gSaveBlock1Ptr->pcItems[b].itemId))
{
CopyItemName(gSaveBlock1Ptr->pcItems[b].itemId, gStringVar1);
ConvertIntToDecimalStringN(gStringVar2, data[2], STR_CONV_MODE_LEFT_ALIGN, 3);
@@ -1335,7 +1335,7 @@ static void ItemStorage_HandleRemoveItem(u8 taskId)
data = gTasks[taskId].data;
if(gMain.newKeys & (A_BUTTON | B_BUTTON))
{
- sub_80D6E48((playerPCItemPageInfo.cursorPos + playerPCItemPageInfo.itemsAbove), data[2]);
+ RemovePCItem((playerPCItemPageInfo.cursorPos + playerPCItemPageInfo.itemsAbove), data[2]);
DestroyListMenuTask(data[5], &(playerPCItemPageInfo.itemsAbove), &(playerPCItemPageInfo.cursorPos));
sub_816C110();
sub_816C140();
diff --git a/src/pokeblock.c b/src/pokeblock.c
index e829452b2..60087b5bf 100644
--- a/src/pokeblock.c
+++ b/src/pokeblock.c
@@ -589,7 +589,7 @@ static void PutPokeblockInfoText(void)
{
u8 i;
- const u8 *itemName = ItemId_GetItem(ITEM_POKEBLOCK_CASE)->name;
+ const u8 *itemName = ItemId_GetName(ITEM_POKEBLOCK_CASE);
PrintOnPokeblockWindow(0, itemName, GetStringCenterAlignXOffset(1, itemName, 0x48));
PrintOnPokeblockWindow(2, gText_Spicy, 0);
diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c
index e7fcce629..f77b7c38c 100644
--- a/src/pokemon_summary_screen.c
+++ b/src/pokemon_summary_screen.c
@@ -3173,11 +3173,11 @@ void sub_81C3554(u8 taskId)
void sub_81C35E4()
{
- u8 *text;
+ const u8 *text;
int offset;
if (gUnknown_0203CF1C->summary.item == ITEM_ENIGMA_BERRY && sub_81B1250() == 1 && (gUnknown_0203CF1C->unk40BE == 1 || gUnknown_0203CF1C->unk40BE == 4 || gUnknown_0203CF1C->unk40BE == 5))
{
- text = (u8*)ItemId_GetItem(ITEM_ENIGMA_BERRY);
+ text = ItemId_GetName(ITEM_ENIGMA_BERRY);
}
else if (gUnknown_0203CF1C->summary.item == ITEM_NONE)
text = gText_None;
diff --git a/src/random.c b/src/random.c
index f2f0ede58..f0b2d9e5f 100644
--- a/src/random.c
+++ b/src/random.c
@@ -7,6 +7,10 @@
EWRAM_DATA static u8 sUnknown = 0;
EWRAM_DATA static u32 sRandCount = 0;
+// IWRAM common
+IWRAM_DATA u32 gRngValue;
+IWRAM_DATA u32 gRng2Value;
+
u16 Random(void)
{
gRngValue = 1103515245 * gRngValue + 24691;
diff --git a/src/save.c b/src/save.c
index 8025d6586..81731692e 100644
--- a/src/save.c
+++ b/src/save.c
@@ -4,17 +4,15 @@
#include "constants/game_stat.h"
#include "task.h"
#include "decompress.h"
+#include "load_save.h"
+#include "overworld.h"
// for the chunk declarations
-extern struct SaveBlock2 gSaveblock2;
-extern struct SaveBlock1 gSaveblock1;
-extern struct PokemonStorage gPokemonStorage;
extern struct SaveSectionLocation gRamSaveSectionLocations[0xE];
-extern u8 gDecompressionBuffer[];
-extern u32 gFlashMemoryPresent;
extern u16 gUnknown_03006294;
extern bool8 gSoftResetDisabled;
+extern u32 gUnknown_0203CF5C;
// Divide save blocks into individual chunks to be written to flash sectors
@@ -24,13 +22,13 @@ extern bool8 gSoftResetDisabled;
/*
* Sector Layout:
- *
+ *
* Sectors 0 - 13: Save Slot 1
* Sectors 14 - 27: Save Slot 2
* Sectors 28 - 29: Hall of Fame
* Sector 30: e-Reader/Mystery Gift Stuff (note: e-Reader is deprecated in Emerald US)
* Sector 31: Recorded Battle
- *
+ *
* There are two save slots for saving the player's game data. We alternate between
* them each time the game is saved, so that if the current save slot is corrupt,
* we can load the previous one. We also rotate the sectors in each save slot
@@ -41,7 +39,7 @@ extern bool8 gSoftResetDisabled;
// (u8 *)structure was removed from the first statement of the macro in Emerald.
// This is because malloc is used to allocate addresses so storing the raw
-// addresses should not be done in the offsets information.
+// addresses should not be done in the offsets information.
#define SAVEBLOCK_CHUNK(structure, chunkNum) \
{ \
chunkNum * SECTOR_DATA_SIZE, \
@@ -69,8 +67,10 @@ const struct SaveSectionOffsets gSaveSectionOffsets[] =
};
extern void DoSaveFailedScreen(u8); // save_failed_screen
-extern void LoadSerializedGame(void); // load_save
extern bool32 ProgramFlashSectorAndVerify(u8 sector, u8 *data);
+extern void save_serialize_map(void);
+extern void sub_800ADF8(void);
+extern bool8 sub_800A520(void);
// iwram common
u16 gLastWrittenSector;
@@ -656,11 +656,6 @@ void UpdateSaveAddresses(void)
}
}
-extern u32 GetGameStat(u8 index); // rom4
-extern void IncrementGameStat(u8 index); // rom4
-extern void SaveSerializedGame(void); // load_save
-extern u32 gUnknown_0203CF5C;
-
u8 HandleSavingData(u8 saveType)
{
u8 i;
@@ -836,7 +831,7 @@ u16 sub_815355C(void)
struct SaveSection* savSection;
savSection = gFastSaveSection = &gSaveDataBuffer;
- if (gFlashMemoryPresent != 1)
+ if (gFlashMemoryPresent != TRUE)
return 0;
UpdateSaveAddresses();
GetSaveValidStatus(gRamSaveSectionLocations);
@@ -897,12 +892,6 @@ u32 sub_8153634(u8 sector, u8* src)
return 1;
}
-extern void save_serialize_map(void);
-extern void sub_8076D5C(void);
-extern void sav2_gender2_inplace_and_xFE(void);
-extern void sub_800ADF8(void);
-extern bool8 sub_800A520(void);
-
void sub_8153688(u8 taskId)
{
s16* taskData = gTasks[taskId].data;
diff --git a/src/secret_base.c b/src/secret_base.c
index c886912f4..cd6143ed0 100644
--- a/src/secret_base.c
+++ b/src/secret_base.c
@@ -327,7 +327,7 @@ void sub_80E8E18(void)
VarSet(VAR_SECRET_BASE_MAP, gMapHeader.regionMapSectionId);
}
-void sub_80E8EE0(struct MapEvents *events)
+void sub_80E8EE0(struct MapEvents const *events)
{
u16 bgEventIndex;
u16 i;
diff --git a/src/trader.c b/src/trader.c
new file mode 100644
index 000000000..c4d70ac9a
--- /dev/null
+++ b/src/trader.c
@@ -0,0 +1,209 @@
+#include "global.h"
+#include "constants/decorations.h"
+#include "constants/mauville_man.h"
+#include "decoration.h"
+#include "decoration_inventory.h"
+#include "event_data.h"
+#include "main.h"
+#include "menu.h"
+#include "menu_helpers.h"
+#include "script.h"
+#include "constants/songs.h"
+#include "sound.h"
+#include "string_util.h"
+#include "strings.h"
+#include "task.h"
+#include "script_menu.h"
+
+static const u8 * const sDefaultTraderNames[] =
+{
+ gText_Tristan,
+ gText_Philip,
+ gText_Dennis,
+ gText_Roberto,
+};
+
+static const u8 sDefaultTraderDecorations[] =
+{
+ DECOR_DUSKULL_DOLL,
+ DECOR_BALL_CUSHION,
+ DECOR_TIRE,
+ DECOR_PRETTY_FLOWERS,
+};
+
+void TraderSetup(void)
+{
+ u8 i;
+ struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader;
+
+ trader->id = MAUVILLE_MAN_TRADER;
+ trader->alreadyTraded = FALSE;
+
+ for (i = 0; i < 4; i++)
+ {
+ StringCopy(trader->playerNames[i], sDefaultTraderNames[i]);
+ trader->decorIds[i] = sDefaultTraderDecorations[i];
+ trader->language[i] = GAME_LANGUAGE;
+ }
+}
+
+void Trader_ResetFlag(void)
+{
+ struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader;
+ trader->alreadyTraded = FALSE;
+}
+
+void CreateAvailableDecorationsMenu(u8 taskId)
+{
+ u8 i;
+ s16 * data = gTasks[taskId].data;
+ struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader;
+ struct WindowTemplate windowTemplate = {0, 1, 1, 10, 10, 15, 1};
+ s32 windowWidth = GetStringWidth(1, gText_Exit, 0);
+ s32 fiveMarksWidth = GetStringWidth(1, gText_FiveMarks, 0);
+ for (i = 0; i < 4; i++)
+ {
+ s32 curWidth;
+ if (trader->decorIds[i] > NUM_DECORATIONS)
+ curWidth = fiveMarksWidth;
+ else
+ curWidth = GetStringWidth(1, gDecorations[trader->decorIds[i]].name, 0);
+ if (curWidth > windowWidth)
+ windowWidth = curWidth;
+ }
+ windowTemplate.width = convert_pixel_width_to_tile_width(windowWidth);
+ data[3] = AddWindow(&windowTemplate);
+ SetWindowBorderStyle(data[3], FALSE, 0x214, 14);
+ for (i = 0; i < 4; i++)
+ {
+ if (trader->decorIds[i] > NUM_DECORATIONS)
+ PrintTextOnWindow(data[3], 1, gText_FiveMarks, 8, 16 * i + 1, 255, NULL);
+ else
+ PrintTextOnWindow(data[3], 1, gDecorations[trader->decorIds[i]].name, 8, 16 * i + 1, 255, NULL);
+ }
+ PrintTextOnWindow(data[3], 1, gText_Exit, 8, 16 * i + 1, 255, NULL);
+ InitMenuInUpperLeftCornerPlaySoundWhenAPressed(data[3], 5, 0);
+ schedule_bg_copy_tilemap_to_vram(0);
+}
+
+void sub_8133BE4(u8 taskId, u8 decorationId)
+{
+ s16 * data = gTasks[taskId].data;
+ if (decorationId > NUM_DECORATIONS)
+ {
+ gSpecialVar_0x8004 = 0xFFFF;
+ }
+ else
+ {
+ gSpecialVar_0x8004 = decorationId;
+ }
+
+ sub_8198070(data[3], FALSE);
+ ClearWindowTilemap(data[3]);
+ RemoveWindow(data[3]);
+ schedule_bg_copy_tilemap_to_vram(0);
+ DestroyTask(taskId);
+ EnableBothScriptContexts();
+}
+
+void Task_HandleGetDecorationMenuInput(u8 taskId)
+{
+ struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader;
+ s8 input = ProcessMenuInput();
+
+ switch (input)
+ {
+ case -2:
+ break;
+ case -1:
+ case 4:
+ PlaySE(SE_SELECT);
+ sub_8133BE4(taskId, 0);
+ break;
+ default:
+ PlaySE(SE_SELECT);
+ gSpecialVar_0x8005 = input;
+ StringCopy(gStringVar1, trader->playerNames[input]);
+ ConvertInternationalString(gStringVar1, trader->language[input]);
+ sub_8133BE4(taskId, trader->decorIds[input]);
+ break;
+ }
+}
+
+void ScrSpecial_GetTraderTradedFlag(void)
+{
+ struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader;
+ gSpecialVar_Result = trader->alreadyTraded;
+}
+
+void ScrSpecial_DoesPlayerHaveNoDecorations(void)
+{
+ u8 i;
+
+ for (i = 0; i < 8; i++)
+ {
+ if (CountDecorationCategoryN(i))
+ {
+ gSpecialVar_Result = FALSE;
+ return;
+ }
+ }
+ gSpecialVar_Result = TRUE;
+}
+
+void ScrSpecial_IsDecorationFull(void)
+{
+ gSpecialVar_Result = FALSE;
+ if (gDecorations[gSpecialVar_0x8004].category != gDecorations[gSpecialVar_0x8006].category
+ && GetFirstEmptyDecorSlot(gDecorations[gSpecialVar_0x8004].category) == -1)
+ {
+ sub_8127250(gStringVar2, gDecorations[gSpecialVar_0x8004].category);
+ gSpecialVar_Result = TRUE;
+ }
+}
+
+void ScrSpecial_TraderMenuGiveDecoration(void)
+{
+ CreateTask(sub_8127208, 0);
+}
+
+void sub_8133DA0(u8 taskId)
+{
+ if (IsSelectedDecorInThePC() == TRUE)
+ {
+ gSpecialVar_0x8006 = gCurDecorInventoryItems[gCurDecorationIndex];
+ StringCopy(gStringVar3, gDecorations[gSpecialVar_0x8004].name);
+ StringCopy(gStringVar2, gDecorations[gSpecialVar_0x8006].name);
+ }
+ else
+ {
+ gSpecialVar_0x8006 = 0xFFFF;
+ }
+ DestroyTask(taskId);
+ EnableBothScriptContexts();
+}
+
+void sub_8133E1C(u8 taskId)
+{
+ gSpecialVar_0x8006 = 0;
+ DestroyTask(taskId);
+ EnableBothScriptContexts();
+}
+
+void ScrSpecial_TraderDoDecorationTrade(void)
+{
+ struct MauvilleOldManTrader *trader = &gSaveBlock1Ptr->oldMan.trader;
+
+ DecorationRemove(gSpecialVar_0x8006);
+ DecorationAdd(gSpecialVar_0x8004);
+ StringCopy(trader->playerNames[gSpecialVar_0x8005], gSaveBlock2Ptr->playerName);
+ trader->decorIds[gSpecialVar_0x8005] = gSpecialVar_0x8006;
+ trader->language[gSpecialVar_0x8005] = GAME_LANGUAGE;
+ trader->alreadyTraded = TRUE;
+}
+
+void ScrSpecial_TraderMenuGetDecoration(void)
+{
+ u8 taskId = CreateTask(Task_HandleGetDecorationMenuInput, 0);
+ CreateAvailableDecorationsMenu(taskId);
+}
diff --git a/src/tv.c b/src/tv.c
index 769bd5080..4b6e682bd 100644
--- a/src/tv.c
+++ b/src/tv.c
@@ -1380,13 +1380,13 @@ void PutFanClubSpecialOnTheAir(void)
StringCopy(show->fanClubSpecial.idolName, name);
tv_store_id_2x(show);
show->fanClubSpecial.language = gGameLanguage;
- if (show->fanClubSpecial.language == LANGUAGE_JAPANESE || gSaveBlock1Ptr->unk_31A0 == LANGUAGE_JAPANESE)
+ if (show->fanClubSpecial.language == LANGUAGE_JAPANESE || gSaveBlock1Ptr->linkBattleRecords.languages[0] == LANGUAGE_JAPANESE)
{
show->fanClubSpecial.idolNameLanguage = LANGUAGE_JAPANESE;
}
else
{
- show->fanClubSpecial.idolNameLanguage = gSaveBlock1Ptr->unk_31A0;
+ show->fanClubSpecial.idolNameLanguage = gSaveBlock1Ptr->linkBattleRecords.languages[0];
}
}
@@ -2465,7 +2465,7 @@ bool8 sub_80EE7C0(void)
{
return TRUE;
}
- if (gSaveBlock1Ptr->linkBattleRecords[0].name[0] == EOS)
+ if (gSaveBlock1Ptr->linkBattleRecords.entries[0].name[0] == EOS)
{
return TRUE;
}
@@ -2945,7 +2945,7 @@ static void sub_80EF40C(u8 varIdx, TVShow *show)
{
if (show->smartshopperShow.itemIds[i] != ITEM_NONE)
{
- price += itemid_get_market_price(show->smartshopperShow.itemIds[i]) * show->smartshopperShow.itemAmounts[i];
+ price += ItemId_GetPrice(show->smartshopperShow.itemIds[i]) * show->smartshopperShow.itemAmounts[i];
}
}
if (show->smartshopperShow.priceReduced == TRUE)
@@ -5120,7 +5120,7 @@ static void DoTVShowTodaysSmartShopper(void)
break;
case 1:
TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language);
- StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[0])->name);
+ StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[0]));
TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[0]);
sTVShowState += 1 + (Random() % 4);
break;
@@ -5148,7 +5148,7 @@ static void DoTVShowTodaysSmartShopper(void)
}
break;
case 6:
- StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[1])->name);
+ StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[1]));
TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[1]);
if (show->smartshopperShow.itemIds[2] != ITEM_NONE)
{
@@ -5164,7 +5164,7 @@ static void DoTVShowTodaysSmartShopper(void)
}
break;
case 7:
- StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[2])->name);
+ StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[2]));
TV_PrintIntToStringVar(2, show->smartshopperShow.itemAmounts[2]);
if (show->smartshopperShow.priceReduced == TRUE)
{
@@ -5201,7 +5201,7 @@ static void DoTVShowTodaysSmartShopper(void)
break;
case 11:
TVShowConvertInternationalString(gStringVar1, show->smartshopperShow.playerName, show->smartshopperShow.language);
- StringCopy(gStringVar2, ItemId_GetItem(show->smartshopperShow.itemIds[0])->name);
+ StringCopy(gStringVar2, ItemId_GetName(show->smartshopperShow.itemIds[0]));
if (show->smartshopperShow.priceReduced == TRUE)
{
sTVShowState = 8;
@@ -5344,7 +5344,7 @@ static void DoTVShowPokemonTodaySuccessfulCapture(void)
sTVShowState = 2;
break;
case 2:
- StringCopy(gStringVar2, ItemId_GetItem(show->pokemonToday.ball)->name);
+ StringCopy(gStringVar2, ItemId_GetName(show->pokemonToday.ball));
TV_PrintIntToStringVar(2, show->pokemonToday.nBallsUsed);
if (show->pokemonToday.nBallsUsed < 4)
{
@@ -6457,7 +6457,7 @@ static void DoTVShowHoennTreasureInvestigators(void)
switch (state)
{
case 0:
- StringCopy(gStringVar1, ItemId_GetItem(show->treasureInvestigators.item)->name);
+ StringCopy(gStringVar1, ItemId_GetName(show->treasureInvestigators.item));
if (show->treasureInvestigators.location == MAPSEC_DYNAMIC)
{
switch (show->treasureInvestigators.mapDataId)
@@ -6476,13 +6476,13 @@ static void DoTVShowHoennTreasureInvestigators(void)
}
break;
case 1:
- StringCopy(gStringVar1, ItemId_GetItem(show->treasureInvestigators.item)->name);
+ StringCopy(gStringVar1, ItemId_GetName(show->treasureInvestigators.item));
TVShowConvertInternationalString(gStringVar2, show->treasureInvestigators.playerName, show->treasureInvestigators.language);
GetMapName(gStringVar3, show->treasureInvestigators.location, 0);
TVShowDone();
break;
case 2:
- StringCopy(gStringVar1, ItemId_GetItem(show->treasureInvestigators.item)->name);
+ StringCopy(gStringVar1, ItemId_GetName(show->treasureInvestigators.item));
TVShowConvertInternationalString(gStringVar2, show->treasureInvestigators.playerName, show->treasureInvestigators.language);
TVShowDone();
break;
@@ -6598,7 +6598,7 @@ static void DoTVShowBreakingNewsTV(void)
break;
case 3:
TV_PrintIntToStringVar(0, show->breakingNews.balls);
- StringCopy(gStringVar2, ItemId_GetItem(show->breakingNews.caughtMonBall)->name);
+ StringCopy(gStringVar2, ItemId_GetName(show->breakingNews.caughtMonBall));
sTVShowState = 4;
break;
case 4:
@@ -6788,7 +6788,7 @@ static void DoTVShowPokemonLotteryWinnerFlashReport(void)
{
StringCopy(gStringVar2, gText_Third);
}
- StringCopy(gStringVar3, ItemId_GetItem(show->lottoWinner.item)->name);
+ StringCopy(gStringVar3, ItemId_GetName(show->lottoWinner.item));
TVShowDone();
ShowFieldMessage(sTVPokemonLotteryWinnerFlashReportTextGroup[state]);
}
@@ -7530,7 +7530,7 @@ static void DoTVShowSecretBaseSecrets(void)
sTVShowState = show->secretBaseSecrets.savedState;
break;
case 19:
- StringCopy(gStringVar2, ItemId_GetItem(show->secretBaseSecrets.item)->name);
+ StringCopy(gStringVar2, ItemId_GetName(show->secretBaseSecrets.item));
sTVShowState = show->secretBaseSecrets.savedState;
break;
case 20: