Clean up Apprentice doc

This commit is contained in:
GriffinR 2019-11-20 19:00:08 -05:00
parent a05006421b
commit b2eb49888d
4 changed files with 167 additions and 141 deletions

View File

@ -10,50 +10,50 @@
#define APPRENTICE_LVL_MODE_50 (FRONTIER_LVL_50 + 1) #define APPRENTICE_LVL_MODE_50 (FRONTIER_LVL_50 + 1)
#define APPRENTICE_LVL_MODE_OPEN (FRONTIER_LVL_OPEN + 1) #define APPRENTICE_LVL_MODE_OPEN (FRONTIER_LVL_OPEN + 1)
#define APPRENTICE_FUNC_GAVE_LVLMODE 0 #define APPRENTICE_FUNC_GAVE_LVLMODE 0
#define APPRENTICE_FUNC_SET_LVLMODE 1 #define APPRENTICE_FUNC_SET_LVLMODE 1
#define APPRENTICE_FUNC_SET_ID 2 #define APPRENTICE_FUNC_SET_ID 2
#define APPRENTICE_FUNC_SHUFFLE_SPECIES 3 #define APPRENTICE_FUNC_SHUFFLE_SPECIES 3
#define APPRENTICE_FUNC_RANDOMIZE_QUESTIONS 4 #define APPRENTICE_FUNC_RANDOMIZE_QUESTIONS 4
#define APPRENTICE_FUNC_ANSWERED_QUESTION 5 #define APPRENTICE_FUNC_ANSWERED_QUESTION 5
#define APPRENTICE_FUNC_IS_FINAL_QUESTION 6 #define APPRENTICE_FUNC_IS_FINAL_QUESTION 6
#define APPRENTICE_FUNC_MENU 7 #define APPRENTICE_FUNC_MENU 7
#define APPRENTICE_FUNC_PRINT_MSG 8 #define APPRENTICE_FUNC_PRINT_MSG 8
#define APPRENTICE_FUNC_RESET 9 #define APPRENTICE_FUNC_RESET 9
#define APPRENTICE_FUNC_CHECK_GONE 10 #define APPRENTICE_FUNC_CHECK_GONE 10
#define APPRENTICE_FUNC_GET_QUESTION 11 #define APPRENTICE_FUNC_GET_QUESTION 11
#define APPRENTICE_FUNC_GET_NUM_PARTY_MONS 12 #define APPRENTICE_FUNC_GET_NUM_PARTY_MONS 12
#define APPRENTICE_FUNC_SET_PARTY_MON 13 #define APPRENTICE_FUNC_SET_PARTY_MON 13
#define APPRENTICE_FUNC_INIT_QUESTION_DATA 14 #define APPRENTICE_FUNC_INIT_QUESTION_DATA 14
#define APPRENTICE_FUNC_FREE_QUESTION_DATA 15 #define APPRENTICE_FUNC_FREE_QUESTION_DATA 15
#define APPRENTICE_FUNC_BUFFER_STRING 16 #define APPRENTICE_FUNC_BUFFER_STRING 16
#define APPRENTICE_FUNC_SET_MOVE 17 #define APPRENTICE_FUNC_SET_MOVE 17
#define APPRENTICE_FUNC_SET_LEAD_MON 18 #define APPRENTICE_FUNC_SET_LEAD_MON 18
#define APPRENTICE_FUNC_OPEN_BAG 19 #define APPRENTICE_FUNC_OPEN_BAG 19
#define APPRENTICE_FUNC_TRY_SET_HELD_ITEM 20 #define APPRENTICE_FUNC_TRY_SET_HELD_ITEM 20
#define APPRENTICE_FUNC_SAVE 21 #define APPRENTICE_FUNC_SAVE 21
#define APPRENTICE_FUNC_SET_GFX_SAVED 22 #define APPRENTICE_FUNC_SET_GFX_SAVED 22
#define APPRENTICE_FUNC_SET_GFX 23 #define APPRENTICE_FUNC_SET_GFX 23
#define APPRENTICE_FUNC_SHOULD_LEAVE 24 #define APPRENTICE_FUNC_SHOULD_LEAVE 24
#define APPRENTICE_FUNC_SHIFT_SAVED 25 #define APPRENTICE_FUNC_SHIFT_SAVED 25
#define APPRENTICE_MSG_PLEASE_TEACH 0 #define APPRENTICE_MSG_PLEASE_TEACH 0
#define APPRENTICE_MSG_REJECT 1 #define APPRENTICE_MSG_REJECT 1
#define APPRENTICE_MSG_WHICH_LVL_MODE 2 #define APPRENTICE_MSG_WHICH_LVL_MODE 2
#define APPRENTICE_MSG_THANKS_LVL_MODE 3 #define APPRENTICE_MSG_THANKS_LVL_MODE 3
#define APPRENTICE_MSG_WHICH_MON_FIRST 4 #define APPRENTICE_MSG_WHICH_MON_FIRST 4
#define APPRENTICE_MSG_THANKS_MON_FIRST 5 #define APPRENTICE_MSG_THANKS_MON_FIRST 5
#define APPRENTICE_MSG_WHICH_MON 6 #define APPRENTICE_MSG_WHICH_MON 6
#define APPRENTICE_MSG_THANKS_MON 7 #define APPRENTICE_MSG_THANKS_MON 7
#define APPRENTICE_MSG_WHICH_MOVE 8 #define APPRENTICE_MSG_WHICH_MOVE 8
#define APPRENTICE_MSG_THANKS_MOVE 9 #define APPRENTICE_MSG_THANKS_MOVE 9
#define APPRENTICE_MSG_WHAT_HELD_ITEM 10 #define APPRENTICE_MSG_WHAT_HELD_ITEM 10
#define APPRENTICE_MSG_PICK_WIN_SPEECH 11 #define APPRENTICE_MSG_PICK_WIN_SPEECH 11
#define APPRENTICE_MSG_THANKS_HELD_ITEM 12 #define APPRENTICE_MSG_THANKS_HELD_ITEM 12
#define APPRENTICE_MSG_HOLD_NOTHING 13 #define APPRENTICE_MSG_HOLD_NOTHING 13
#define APPRENTICE_MSG_THANKS_NO_HELD_ITEM 14 #define APPRENTICE_MSG_THANKS_NO_HELD_ITEM 14
#define APPRENTICE_MSG_THANKS_WIN_SPEECH 15 #define APPRENTICE_MSG_THANKS_WIN_SPEECH 15
#define APPRENTICE_MSG_ITEM_ALREADY_SUGGESTED 16 #define APPRENTICE_MSG_ITEM_ALREADY_SUGGESTED 16
#define APPRENTICE_QUESTION_WHICH_FIRST 1 #define APPRENTICE_QUESTION_WHICH_FIRST 1
#define APPRENTICE_QUESTION_WHICH_MON 2 #define APPRENTICE_QUESTION_WHICH_MON 2
@ -61,31 +61,28 @@
#define APPRENTICE_QUESTION_WHAT_ITEM 4 #define APPRENTICE_QUESTION_WHAT_ITEM 4
#define APPRENTICE_QUESTION_WIN_SPEECH 5 #define APPRENTICE_QUESTION_WIN_SPEECH 5
// Would be redundant with the above if they used the same values // Would be redundant with the above set if they used the same values
// but they do this to skip the "which mon" questions and store the below id in a 2 bit field
// These IDs are randomly shuffled in an array to determine the order of questions asked by the Apprentice
// The last question asked is always picking their win speech
#define QUESTION_ID_WIN_SPEECH 0 #define QUESTION_ID_WIN_SPEECH 0
#define QUESTION_ID_WHAT_ITEM 1 #define QUESTION_ID_WHAT_ITEM 1
#define QUESTION_ID_WHICH_MOVE 2 #define QUESTION_ID_WHICH_MOVE 2
#define QUESTION_ID_WHICH_FIRST 3 #define QUESTION_ID_WHICH_FIRST 3
#define APPRENTICE_ASK_WHICH_LEVEL 0 #define APPRENTICE_ASK_WHICH_LEVEL 0
#define APPRENTICE_ASK_3SPECIES 1 #define APPRENTICE_ASK_3SPECIES 1
#define APPRENTICE_ASK_2SPECIES 2 #define APPRENTICE_ASK_2SPECIES 2
#define APPRENTICE_ASK_MOVES 3 #define APPRENTICE_ASK_MOVES 3
#define APPRENTICE_ASK_GIVE 4 #define APPRENTICE_ASK_GIVE 4
#define APPRENTICE_ASK_YES_NO 6 #define APPRENTICE_ASK_YES_NO 6
#define APPRENTICE_BUFF_SPECIES1 0 #define APPRENTICE_BUFF_SPECIES1 0
#define APPRENTICE_BUFF_SPECIES2 1 #define APPRENTICE_BUFF_SPECIES2 1
#define APPRENTICE_BUFF_SPECIES3 2 #define APPRENTICE_BUFF_SPECIES3 2
#define APPRENTICE_BUFF_MOVE1 3 #define APPRENTICE_BUFF_MOVE1 3
#define APPRENTICE_BUFF_MOVE2 4 #define APPRENTICE_BUFF_MOVE2 4
#define APPRENTICE_BUFF_ITEM 5 #define APPRENTICE_BUFF_ITEM 5
#define APPRENTICE_BUFF_NAME 6 #define APPRENTICE_BUFF_NAME 6
#define APPRENTICE_BUFF_WIN_SPEECH 7 #define APPRENTICE_BUFF_WIN_SPEECH 7
#define APPRENTICE_BUFF_LEVEL 8 #define APPRENTICE_BUFF_LEVEL 8
#define APPRENTICE_BUFF_LEAD_MON_SPECIES 9 #define APPRENTICE_BUFF_LEAD_MON_SPECIES 9
#endif // GUARD_CONSTANTS_APPRENTICE_H #endif // GUARD_CONSTANTS_APPRENTICE_H

View File

@ -419,7 +419,7 @@ struct PlayersApprentice
/*0xB1*/ u8 questionsAnswered:4; /*0xB1*/ u8 questionsAnswered:4;
/*0xB1*/ u8 leadMonId:2; /*0xB1*/ u8 leadMonId:2;
/*0xB2*/ u8 party:3; /*0xB2*/ u8 party:3;
/*0xB2*/ u8 field_B2_1:2; /*0xB2*/ u8 saveId:2;
/*0xB3*/ u8 unused; /*0xB3*/ u8 unused;
/*0xB4*/ u8 speciesIds[MULTI_PARTY_SIZE]; /*0xB4*/ u8 speciesIds[MULTI_PARTY_SIZE];
/*0xB8*/ struct ApprenticeQuestion questions[APPRENTICE_MAX_QUESTIONS]; /*0xB8*/ struct ApprenticeQuestion questions[APPRENTICE_MAX_QUESTIONS];

View File

@ -31,10 +31,37 @@
#include "constants/trainers.h" #include "constants/trainers.h"
#include "constants/moves.h" #include "constants/moves.h"
/* Summary of Apprentice, because (as of writing at least) its not very well documented online
*
* ## Basic info
* In the Battle Tower lobby there is an NPC which asks to be taught by the player
* They can be any 1 of 16 NPC trainers, each with their own name, class, and set of possible party species
* They ask the player a series of questions once per day, and eventually depart the lobby to be replaced by a new Apprentice
*
* ## Initial Questions
* The first question they always ask is a request to be taught, which cannot be rejected
* The second question (which follows immediately after) is whether they should participate in Battle Tower Lv 50 or Open Lv
* After these opening questions they always ask the player to choose between 2 mons, which they repeat 3 times
*
* ## Random Questions
* After choosing 3 mons for them, the Apprentice will randomly ask between 1 and 8 questions of 4 different types, as follows
* - Asking which mon to lead with, which they will only ask at most once
* - Asking which move a mon should use, which they will ask at most 5 times
* - Asking what held item to give to a mon, which they will ask at most 3 times (once for each mon)
* - Asking what they should say when they win a battle, which will always be their final question before departing
*
* ## After departing
* After telling them what they should say when they win a battle they will leave the lobby for a final time
* They will then be replaced by a new random Apprentice (they can repeat)
* Up to 4 old Apprentices are saved and can be encountered (or partnered with) during challenges of the mode they were told to battle in
* They can also be record mixed to and from other Emerald games
* Old/record mixed Apprentices are stored in struct Apprentice apprentices of SaveBlock2
* and the current Apprentice is stored in struct PlayersApprentice playerApprentice of SaveBlock2
*/
#define PLAYER_APPRENTICE gSaveBlock2Ptr->playerApprentice #define PLAYER_APPRENTICE gSaveBlock2Ptr->playerApprentice
#define CURRENT_QUESTION_NUM PLAYER_APPRENTICE.questionsAnswered - NUM_WHICH_MON_QUESTIONS #define CURRENT_QUESTION_NUM PLAYER_APPRENTICE.questionsAnswered - NUM_WHICH_MON_QUESTIONS
// The below a TODO
struct ApprenticePartyMovesData struct ApprenticePartyMovesData
{ {
u8 moveCounter; u8 moveCounter;
@ -373,8 +400,8 @@ static void GetShouldCheckApprenticeGone(void);
static void ApprenticeGetQuestion(void); static void ApprenticeGetQuestion(void);
static void GetNumApprenticePartyMonsAssigned(void); static void GetNumApprenticePartyMonsAssigned(void);
static void SetApprenticePartyMon(void); static void SetApprenticePartyMon(void);
static void InitApprenticeQuestionData(void); static void InitQuestionData(void);
static void FreeApprenticeQuestionData(void); static void FreeQuestionData(void);
static void ApprenticeBufferString(void); static void ApprenticeBufferString(void);
static void SetApprenticeMonMove(void); static void SetApprenticeMonMove(void);
static void SetLeadApprenticeMon(void); static void SetLeadApprenticeMon(void);
@ -1044,32 +1071,32 @@ static const u8 sQuestionPossibilities[] =
static void (* const sApprenticeFunctions[])(void) = static void (* const sApprenticeFunctions[])(void) =
{ {
[APPRENTICE_FUNC_GAVE_LVLMODE] = Script_GivenApprenticeLvlMode, [APPRENTICE_FUNC_GAVE_LVLMODE] = Script_GivenApprenticeLvlMode,
[APPRENTICE_FUNC_SET_LVLMODE] = Script_SetApprenticeLvlMode, [APPRENTICE_FUNC_SET_LVLMODE] = Script_SetApprenticeLvlMode,
[APPRENTICE_FUNC_SET_ID] = Script_SetApprenticeId, [APPRENTICE_FUNC_SET_ID] = Script_SetApprenticeId,
[APPRENTICE_FUNC_SHUFFLE_SPECIES] = ShuffleApprenticeSpecies, [APPRENTICE_FUNC_SHUFFLE_SPECIES] = ShuffleApprenticeSpecies,
[APPRENTICE_FUNC_RANDOMIZE_QUESTIONS] = Script_SetRandomQuestionData, [APPRENTICE_FUNC_RANDOMIZE_QUESTIONS] = Script_SetRandomQuestionData,
[APPRENTICE_FUNC_ANSWERED_QUESTION] = IncrementQuestionsAnswered, [APPRENTICE_FUNC_ANSWERED_QUESTION] = IncrementQuestionsAnswered,
[APPRENTICE_FUNC_IS_FINAL_QUESTION] = IsFinalQuestion, [APPRENTICE_FUNC_IS_FINAL_QUESTION] = IsFinalQuestion,
[APPRENTICE_FUNC_MENU] = Script_CreateApprenticeMenu, [APPRENTICE_FUNC_MENU] = Script_CreateApprenticeMenu,
[APPRENTICE_FUNC_PRINT_MSG] = Script_PrintApprenticeMessage, [APPRENTICE_FUNC_PRINT_MSG] = Script_PrintApprenticeMessage,
[APPRENTICE_FUNC_RESET] = Script_ResetPlayerApprentice, [APPRENTICE_FUNC_RESET] = Script_ResetPlayerApprentice,
[APPRENTICE_FUNC_CHECK_GONE] = GetShouldCheckApprenticeGone, [APPRENTICE_FUNC_CHECK_GONE] = GetShouldCheckApprenticeGone,
[APPRENTICE_FUNC_GET_QUESTION] = ApprenticeGetQuestion, [APPRENTICE_FUNC_GET_QUESTION] = ApprenticeGetQuestion,
[APPRENTICE_FUNC_GET_NUM_PARTY_MONS] = GetNumApprenticePartyMonsAssigned, [APPRENTICE_FUNC_GET_NUM_PARTY_MONS] = GetNumApprenticePartyMonsAssigned,
[APPRENTICE_FUNC_SET_PARTY_MON] = SetApprenticePartyMon, [APPRENTICE_FUNC_SET_PARTY_MON] = SetApprenticePartyMon,
[APPRENTICE_FUNC_INIT_QUESTION_DATA] = InitApprenticeQuestionData, [APPRENTICE_FUNC_INIT_QUESTION_DATA] = InitQuestionData,
[APPRENTICE_FUNC_FREE_QUESTION_DATA] = FreeApprenticeQuestionData, [APPRENTICE_FUNC_FREE_QUESTION_DATA] = FreeQuestionData,
[APPRENTICE_FUNC_BUFFER_STRING] = ApprenticeBufferString, [APPRENTICE_FUNC_BUFFER_STRING] = ApprenticeBufferString,
[APPRENTICE_FUNC_SET_MOVE] = SetApprenticeMonMove, [APPRENTICE_FUNC_SET_MOVE] = SetApprenticeMonMove,
[APPRENTICE_FUNC_SET_LEAD_MON] = SetLeadApprenticeMon, [APPRENTICE_FUNC_SET_LEAD_MON] = SetLeadApprenticeMon,
[APPRENTICE_FUNC_OPEN_BAG] = Script_ApprenticeOpenBagMenu, [APPRENTICE_FUNC_OPEN_BAG] = Script_ApprenticeOpenBagMenu,
[APPRENTICE_FUNC_TRY_SET_HELD_ITEM] = TrySetApprenticeHeldItem, [APPRENTICE_FUNC_TRY_SET_HELD_ITEM] = TrySetApprenticeHeldItem,
[APPRENTICE_FUNC_SAVE] = SaveApprentice, [APPRENTICE_FUNC_SAVE] = SaveApprentice,
[APPRENTICE_FUNC_SET_GFX_SAVED] = SetSavedApprenticeTrainerGfxId, [APPRENTICE_FUNC_SET_GFX_SAVED] = SetSavedApprenticeTrainerGfxId,
[APPRENTICE_FUNC_SET_GFX] = SetPlayerApprenticeTrainerGfxId, [APPRENTICE_FUNC_SET_GFX] = SetPlayerApprenticeTrainerGfxId,
[APPRENTICE_FUNC_SHOULD_LEAVE] = GetShouldApprenticeLeave, [APPRENTICE_FUNC_SHOULD_LEAVE] = GetShouldApprenticeLeave,
[APPRENTICE_FUNC_SHIFT_SAVED] = ShiftSavedApprentices, [APPRENTICE_FUNC_SHIFT_SAVED] = ShiftSavedApprentices,
}; };
// The first Apprentice can only be one of these // The first Apprentice can only be one of these
@ -1079,7 +1106,7 @@ static const u8 sInitialApprenticeIds[8] = {0, 1, 2, 3, 6, 7, 8, 9};
void BufferApprenticeChallengeText(u8 saveApprenticeId) void BufferApprenticeChallengeText(u8 saveApprenticeId)
{ {
u8 i, num; u8 i, num;
const u8 *Intro; const u8 *challengeText;
num = gSaveBlock2Ptr->apprentices[saveApprenticeId].number; num = gSaveBlock2Ptr->apprentices[saveApprenticeId].number;
for (i = 0; num != 0 && i < APPRENTICE_COUNT; num /= 10, i++) for (i = 0; num != 0 && i < APPRENTICE_COUNT; num /= 10, i++)
@ -1088,8 +1115,8 @@ void BufferApprenticeChallengeText(u8 saveApprenticeId)
StringCopy7(gStringVar1, gSaveBlock2Ptr->apprentices[saveApprenticeId].playerName); StringCopy7(gStringVar1, gSaveBlock2Ptr->apprentices[saveApprenticeId].playerName);
ConvertInternationalString(gStringVar1, gSaveBlock2Ptr->apprentices[saveApprenticeId].language); ConvertInternationalString(gStringVar1, gSaveBlock2Ptr->apprentices[saveApprenticeId].language);
ConvertIntToDecimalStringN(gStringVar2, gSaveBlock2Ptr->apprentices[saveApprenticeId].number, STR_CONV_MODE_RIGHT_ALIGN, i); ConvertIntToDecimalStringN(gStringVar2, gSaveBlock2Ptr->apprentices[saveApprenticeId].number, STR_CONV_MODE_RIGHT_ALIGN, i);
Intro = sApprenticeChallengeTexts[gSaveBlock2Ptr->apprentices[saveApprenticeId].id]; challengeText = sApprenticeChallengeTexts[gSaveBlock2Ptr->apprentices[saveApprenticeId].id];
StringExpandPlaceholders(gStringVar4, Intro); StringExpandPlaceholders(gStringVar4, challengeText);
} }
void Apprentice_EnableBothScriptContexts(void) void Apprentice_EnableBothScriptContexts(void)
@ -1112,7 +1139,7 @@ void ResetAllApprenticeData(void)
{ {
u8 i, j; u8 i, j;
PLAYER_APPRENTICE.field_B2_1 = 0; PLAYER_APPRENTICE.saveId = 0;
for (i = 0; i < APPRENTICE_COUNT; i++) for (i = 0; i < APPRENTICE_COUNT; i++)
{ {
for (j = 0; j < ARRAY_COUNT(gSaveBlock2Ptr->apprentices[i].speechWon); j++) for (j = 0; j < ARRAY_COUNT(gSaveBlock2Ptr->apprentices[i].speechWon); j++)
@ -1944,7 +1971,7 @@ static void SetApprenticeMonMove(void)
} }
} }
static void InitApprenticeQuestionData(void) static void InitQuestionData(void)
{ {
u8 i; u8 i;
u8 count = 0; u8 count = 0;
@ -1994,7 +2021,7 @@ static void InitApprenticeQuestionData(void)
} }
} }
static void FreeApprenticeQuestionData(void) static void FreeQuestionData(void)
{ {
FREE_AND_SET_NULL(gApprenticeQuestionData); FREE_AND_SET_NULL(gApprenticeQuestionData);
} }

View File

@ -69,7 +69,7 @@ struct PlayerRecordsEmerald
/* 0x1124 */ struct EmeraldBattleTowerRecord battleTowerRecord; /* 0x1124 */ struct EmeraldBattleTowerRecord battleTowerRecord;
/* 0x1210 */ u16 giftItem; /* 0x1210 */ u16 giftItem;
/* 0x1214 */ LilycoveLady lilycoveLady; /* 0x1214 */ LilycoveLady lilycoveLady;
/* 0x1254 */ struct Apprentice apprentice[2]; /* 0x1254 */ struct Apprentice apprentices[2];
/* 0x12dc */ struct PlayerHallRecords hallRecords; /* 0x12dc */ struct PlayerHallRecords hallRecords;
/* 0x1434 */ u8 field_1434[0x10]; /* 0x1434 */ u8 field_1434[0x10];
}; // 0x1444 }; // 0x1444
@ -120,8 +120,8 @@ static void sub_80E7B2C(const u8 *);
static void ReceiveDaycareMailData(struct RecordMixingDayCareMail *, size_t, u8, TVShow *); static void ReceiveDaycareMailData(struct RecordMixingDayCareMail *, size_t, u8, TVShow *);
static void ReceiveGiftItem(u16 *item, u8 which); static void ReceiveGiftItem(u16 *item, u8 which);
static void Task_DoRecordMixing(u8 taskId); static void Task_DoRecordMixing(u8 taskId);
static void sub_80E8110(struct Apprentice *arg0, struct Apprentice *arg1); static void GetSavedApprentices(struct Apprentice *dst, struct Apprentice *src);
static void ReceiveApprenticeData(struct Apprentice *arg0, size_t arg1, u32 arg2); static void ReceiveApprenticeData(struct Apprentice *mixApprentice, size_t recordSize, u32 multiplayerId);
static void ReceiveRankingHallRecords(struct PlayerHallRecords *hallRecords, size_t arg1, u32 arg2); static void ReceiveRankingHallRecords(struct PlayerHallRecords *hallRecords, size_t arg1, u32 arg2);
static void sub_80E89F8(struct RecordMixingDayCareMail *dst); static void sub_80E89F8(struct RecordMixingDayCareMail *dst);
static void SanitizeDayCareMailForRuby(struct RecordMixingDayCareMail *src); static void SanitizeDayCareMailForRuby(struct RecordMixingDayCareMail *src);
@ -252,7 +252,7 @@ static void PrepareExchangePacket(void)
if (GetMultiplayerId() == 0) if (GetMultiplayerId() == 0)
sSentRecord->emerald.giftItem = GetRecordMixingGift(); sSentRecord->emerald.giftItem = GetRecordMixingGift();
sub_80E8110(sSentRecord->emerald.apprentice, sApprenticesSave); GetSavedApprentices(sSentRecord->emerald.apprentices, sApprenticesSave);
GetPlayerHallRecords(&sSentRecord->emerald.hallRecords); GetPlayerHallRecords(&sSentRecord->emerald.hallRecords);
} }
} }
@ -285,7 +285,7 @@ static void ReceiveExchangePacket(u32 which)
ReceiveBattleTowerData(&sReceivedRecords->emerald.battleTowerRecord, sizeof(struct PlayerRecordsEmerald), which); ReceiveBattleTowerData(&sReceivedRecords->emerald.battleTowerRecord, sizeof(struct PlayerRecordsEmerald), which);
ReceiveGiftItem(&sReceivedRecords->emerald.giftItem, which); ReceiveGiftItem(&sReceivedRecords->emerald.giftItem, which);
ReceiveLilycoveLadyData(&sReceivedRecords->emerald.lilycoveLady, sizeof(struct PlayerRecordsEmerald), which); ReceiveLilycoveLadyData(&sReceivedRecords->emerald.lilycoveLady, sizeof(struct PlayerRecordsEmerald), which);
ReceiveApprenticeData(sReceivedRecords->emerald.apprentice, sizeof(struct PlayerRecordsEmerald), (u8) which); ReceiveApprenticeData(sReceivedRecords->emerald.apprentices, sizeof(struct PlayerRecordsEmerald), (u8) which);
ReceiveRankingHallRecords(&sReceivedRecords->emerald.hallRecords, sizeof(struct PlayerRecordsEmerald), (u8) which); ReceiveRankingHallRecords(&sReceivedRecords->emerald.hallRecords, sizeof(struct PlayerRecordsEmerald), (u8) which);
} }
} }
@ -651,7 +651,7 @@ static void ReceiveBattleTowerData(void *battleTowerRecord, size_t recordSize, u
{ {
struct EmeraldBattleTowerRecord *dest; struct EmeraldBattleTowerRecord *dest;
struct BattleTowerPokemon *btPokemon; struct BattleTowerPokemon *btPokemon;
u32 mixIndices[4]; u32 mixIndices[MAX_LINK_PLAYERS];
s32 i; s32 i;
ShufflePlayerIndices(mixIndices); ShufflePlayerIndices(mixIndices);
@ -682,7 +682,7 @@ static void ReceiveBattleTowerData(void *battleTowerRecord, size_t recordSize, u
static void ReceiveLilycoveLadyData(LilycoveLady *lilycoveLady, size_t recordSize, u8 which) static void ReceiveLilycoveLadyData(LilycoveLady *lilycoveLady, size_t recordSize, u8 which)
{ {
LilycoveLady *dest; LilycoveLady *dest;
u32 mixIndices[4]; u32 mixIndices[MAX_LINK_PLAYERS];
ShufflePlayerIndices(mixIndices); ShufflePlayerIndices(mixIndices);
memcpy((void *)lilycoveLady + recordSize * which, sLilycoveLadySave, sizeof(LilycoveLady)); memcpy((void *)lilycoveLady + recordSize * which, sLilycoveLadySave, sizeof(LilycoveLady));
@ -1018,57 +1018,59 @@ static void Task_DoRecordMixing(u8 taskId)
// New Emerald functions // New Emerald functions
static void sub_80E8110(struct Apprentice *dst, struct Apprentice *src) static void GetSavedApprentices(struct Apprentice *dst, struct Apprentice *src)
{ {
s32 i, id; s32 i, id;
s32 var_2C, var_28, var_24, r8; s32 apprenticeSaveId, oldPlayerApprenticeSaveId;
s32 numOldPlayerApprentices, numMixApprentices;
dst[0].playerName[0] = EOS; dst[0].playerName[0] = EOS;
dst[1].playerName[0] = EOS; dst[1].playerName[0] = EOS;
dst[0] = src[0]; dst[0] = src[0];
var_28 = 0; oldPlayerApprenticeSaveId = 0;
var_24 = 0; numOldPlayerApprentices = 0;
var_2C = 0; apprenticeSaveId = 0;
r8 = 0; numMixApprentices = 0;
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
id = ((i + gSaveBlock2Ptr->playerApprentice.field_B2_1) % 3) + 1; id = ((i + gSaveBlock2Ptr->playerApprentice.saveId) % 3) + 1;
if (src[id].playerName[0] != EOS) if (src[id].playerName[0] != EOS)
{ {
if (GetTrainerId(src[id].playerId) != GetTrainerId(gSaveBlock2Ptr->playerTrainerId)) if (GetTrainerId(src[id].playerId) != GetTrainerId(gSaveBlock2Ptr->playerTrainerId))
{ {
r8++; numMixApprentices++;
var_2C = id; apprenticeSaveId = id;
} }
if (GetTrainerId(src[id].playerId) == GetTrainerId(gSaveBlock2Ptr->playerTrainerId)) if (GetTrainerId(src[id].playerId) == GetTrainerId(gSaveBlock2Ptr->playerTrainerId))
{ {
var_24++; numOldPlayerApprentices++;
var_28 = id; oldPlayerApprenticeSaveId = id;
} }
} }
} }
if (r8 == 0 && var_24 != 0) // Prefer passing on other mixed Apprentices rather than old player's Apprentices
if (numMixApprentices == 0 && numOldPlayerApprentices != 0)
{ {
r8 = var_24; numMixApprentices = numOldPlayerApprentices;
var_2C = var_28; apprenticeSaveId = oldPlayerApprenticeSaveId;
} }
switch (r8) switch (numMixApprentices)
{ {
case 1: case 1:
dst[1] = src[var_2C]; dst[1] = src[apprenticeSaveId];
break; break;
case 2: case 2:
if (Random2() > 0x3333) if (Random2() > 0x3333)
{ {
dst[1] = src[gSaveBlock2Ptr->playerApprentice.field_B2_1 + 1]; dst[1] = src[gSaveBlock2Ptr->playerApprentice.saveId + 1];
} }
else else
{ {
dst[1] = src[((gSaveBlock2Ptr->playerApprentice.field_B2_1 + 1) % 3 + 1)]; dst[1] = src[((gSaveBlock2Ptr->playerApprentice.saveId + 1) % 3 + 1)];
} }
break; break;
} }
@ -1113,7 +1115,7 @@ void GetPlayerHallRecords(struct PlayerHallRecords *dst)
} }
} }
static bool32 sub_80E841C(struct Apprentice *mixApprentice, struct Apprentice *apprentices) static bool32 IsApprenticeAlreadySaved(struct Apprentice *mixApprentice, struct Apprentice *apprentices)
{ {
s32 i; s32 i;
@ -1129,40 +1131,40 @@ static bool32 sub_80E841C(struct Apprentice *mixApprentice, struct Apprentice *a
return FALSE; return FALSE;
} }
static void ReceiveApprenticeData(struct Apprentice *arg0, size_t arg1, u32 arg2) static void ReceiveApprenticeData(struct Apprentice *mixApprentice, size_t recordSize, u32 multiplayerId)
{ {
s32 i, r7, r8; s32 i, numApprentices, apprenticeId;
struct Apprentice *structPtr; struct Apprentice *mixApprenticePtr;
u32 mixIndices[4]; u32 mixIndices[MAX_LINK_PLAYERS];
u32 structId; u32 apprenticeSaveId;
ShufflePlayerIndices(mixIndices); ShufflePlayerIndices(mixIndices);
structPtr = (void*)(arg0) + (arg1 * mixIndices[arg2]); mixApprenticePtr = (void*)(mixApprentice) + (recordSize * mixIndices[multiplayerId]);
r7 = 0; numApprentices = 0;
r8 = 0; apprenticeId = 0;
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
if (structPtr[i].playerName[0] != EOS && !sub_80E841C(&structPtr[i], &gSaveBlock2Ptr->apprentices[0])) if (mixApprenticePtr[i].playerName[0] != EOS && !IsApprenticeAlreadySaved(&mixApprenticePtr[i], &gSaveBlock2Ptr->apprentices[0]))
{ {
r7++; numApprentices++;
r8 = i; apprenticeId = i;
} }
} }
switch (r7) switch (numApprentices)
{ {
case 1: case 1:
structId = gSaveBlock2Ptr->playerApprentice.field_B2_1 + 1; apprenticeSaveId = gSaveBlock2Ptr->playerApprentice.saveId + 1;
gSaveBlock2Ptr->apprentices[structId] = structPtr[r8]; gSaveBlock2Ptr->apprentices[apprenticeSaveId] = mixApprenticePtr[apprenticeId];
gSaveBlock2Ptr->playerApprentice.field_B2_1 = (gSaveBlock2Ptr->playerApprentice.field_B2_1 + 1) % 3; gSaveBlock2Ptr->playerApprentice.saveId = (gSaveBlock2Ptr->playerApprentice.saveId + 1) % 3;
break; break;
case 2: case 2:
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
structId = ((i ^ 1) + gSaveBlock2Ptr->playerApprentice.field_B2_1) % 3 + 1; apprenticeSaveId = ((i ^ 1) + gSaveBlock2Ptr->playerApprentice.saveId) % 3 + 1;
gSaveBlock2Ptr->apprentices[structId] = structPtr[i]; gSaveBlock2Ptr->apprentices[apprenticeSaveId] = mixApprenticePtr[i];
} }
gSaveBlock2Ptr->playerApprentice.field_B2_1 = (gSaveBlock2Ptr->playerApprentice.field_B2_1 + 2) % 3; gSaveBlock2Ptr->playerApprentice.saveId = (gSaveBlock2Ptr->playerApprentice.saveId + 2) % 3;
break; break;
} }
} }