Initial mystery gift sync
This commit is contained in:
+309
-279
@@ -19,6 +19,8 @@
|
||||
#include "mystery_gift.h"
|
||||
#include "strings.h"
|
||||
|
||||
#define CALC_CRC(data) CalcCRC16WithTable((void *)&(data), sizeof(data))
|
||||
|
||||
struct MEventTaskData1
|
||||
{
|
||||
u16 stateAdvanceDelay;
|
||||
@@ -36,44 +38,44 @@ struct MEventTaskData1
|
||||
};
|
||||
|
||||
static void Task_EReaderComm(u8 taskId);
|
||||
static bool32 IsReceivedWonderNewsHeaderValid(const struct WonderNews * src);
|
||||
static void BlankWonderNews(void);
|
||||
static void BlankMENewsJisan(void);
|
||||
static bool32 IsReceivedWonderCardHeaderValid(const struct WonderCard * src);
|
||||
static void BlankSavedWonderCard(void);
|
||||
static void BlankMEventBuffer2(void);
|
||||
static void RecordIdOfWonderCardSender(u32 eventId, u32 trainerId, u32 *idsList, s32 count);
|
||||
static void BlankBuffer344(void);
|
||||
static bool32 ValidateWonderNews(const struct WonderNews * src);
|
||||
static void ClearSavedWonderNews(void);
|
||||
static void ClearSavedWonderNewsMetadata(void);
|
||||
static bool32 ValidateWonderCard(const struct WonderCard * src);
|
||||
static void ClearSavedWonderCard(void);
|
||||
static void ClearSavedWonderCardMetadata(void);
|
||||
static void IncrementCardStatForNewTrainer(u32 eventId, u32 trainerId, u32 *idsList, s32 count);
|
||||
static void ClearSavedTrainerIds(void);
|
||||
|
||||
extern const u8 gMultiBootProgram_EReader_Start[];
|
||||
extern const u8 gMultiBootProgram_EReader_End[];
|
||||
|
||||
static const u16 sGiftItemFlagIds[] = {
|
||||
FLAG_GOT_AURORA_TICKET,
|
||||
FLAG_GOT_MYSTIC_TICKET,
|
||||
FLAG_0x2A9,
|
||||
FLAG_0x2AA,
|
||||
FLAG_0x2AB,
|
||||
FLAG_0x2AC,
|
||||
FLAG_0x2AD,
|
||||
FLAG_0x2AE,
|
||||
FLAG_0x2AF,
|
||||
FLAG_0x2B0,
|
||||
FLAG_0x2B1,
|
||||
FLAG_0x2B2,
|
||||
FLAG_0x2B3,
|
||||
FLAG_0x2B4,
|
||||
FLAG_0x2B5,
|
||||
FLAG_0x2B6,
|
||||
FLAG_0x2B7,
|
||||
FLAG_0x2B8,
|
||||
FLAG_0x2B9,
|
||||
FLAG_0x2BA
|
||||
static const u16 sReceivedGiftFlags[] = {
|
||||
FLAG_RECEIVED_AURORA_TICKET,
|
||||
FLAG_RECEIVED_MYSTIC_TICKET,
|
||||
FLAG_RECEIVED_OLD_SEA_MAP, // Not used until Emerald
|
||||
FLAG_WONDER_CARD_UNUSED_1,
|
||||
FLAG_WONDER_CARD_UNUSED_2,
|
||||
FLAG_WONDER_CARD_UNUSED_3,
|
||||
FLAG_WONDER_CARD_UNUSED_4,
|
||||
FLAG_WONDER_CARD_UNUSED_5,
|
||||
FLAG_WONDER_CARD_UNUSED_6,
|
||||
FLAG_WONDER_CARD_UNUSED_7,
|
||||
FLAG_WONDER_CARD_UNUSED_8,
|
||||
FLAG_WONDER_CARD_UNUSED_9,
|
||||
FLAG_WONDER_CARD_UNUSED_10,
|
||||
FLAG_WONDER_CARD_UNUSED_11,
|
||||
FLAG_WONDER_CARD_UNUSED_12,
|
||||
FLAG_WONDER_CARD_UNUSED_13,
|
||||
FLAG_WONDER_CARD_UNUSED_14,
|
||||
FLAG_WONDER_CARD_UNUSED_15,
|
||||
FLAG_WONDER_CARD_UNUSED_16,
|
||||
FLAG_WONDER_CARD_UNUSED_17
|
||||
};
|
||||
|
||||
struct MEvent_Str_1 sMEventSendToEReaderManager;
|
||||
|
||||
static EWRAM_DATA bool32 sReceivedWonderCardIsValid = FALSE;
|
||||
static EWRAM_DATA bool32 sStatsEnabled = FALSE;
|
||||
|
||||
void SendUnknownSerialData_Init(struct MEvent_Str_1 *mgr, size_t size, const void *data)
|
||||
{
|
||||
@@ -475,11 +477,11 @@ static void Task_EReaderComm(u8 taskId)
|
||||
}
|
||||
}
|
||||
|
||||
void InitMEventData(void)
|
||||
void ClearMysteryGift(void)
|
||||
{
|
||||
CpuFill32(0, &gSaveBlock1Ptr->mysteryGift, sizeof(gSaveBlock1Ptr->mysteryGift));
|
||||
BlankMENewsJisan();
|
||||
EC_ResetMEventProfileMaybe();
|
||||
ClearSavedWonderNewsMetadata();
|
||||
InitQuestionnaireWords();
|
||||
}
|
||||
|
||||
struct WonderNews * GetSavedWonderNews(void)
|
||||
@@ -492,301 +494,310 @@ struct WonderCard * GetSavedWonderCard(void)
|
||||
return &gSaveBlock1Ptr->mysteryGift.card;
|
||||
}
|
||||
|
||||
struct WonderCardMetadata * sav1_get_mevent_buffer_2(void)
|
||||
struct WonderCardMetadata * GetSavedWonderCardMetadata(void)
|
||||
{
|
||||
return &gSaveBlock1Ptr->mysteryGift.cardMetadata;
|
||||
}
|
||||
|
||||
struct WonderNewsMetadata * GetMENewsJisanStructPtr(void)
|
||||
struct WonderNewsMetadata * GetSavedWonderNewsMetadata(void)
|
||||
{
|
||||
return &gSaveBlock1Ptr->mysteryGift.newsMetadata;
|
||||
}
|
||||
|
||||
u16 * GetMEventProfileECWordsMaybe(void)
|
||||
u16 * GetQuestionnaireWordsPtr(void)
|
||||
{
|
||||
return gSaveBlock1Ptr->mysteryGift.questionnaireWords;
|
||||
}
|
||||
|
||||
void DestroyWonderNews(void)
|
||||
// Equivalent to ClearSavedWonderCardAndRelated, but nothing else to clear
|
||||
void ClearSavedWonderNewsAndRelated(void)
|
||||
{
|
||||
BlankWonderNews();
|
||||
ClearSavedWonderNews();
|
||||
}
|
||||
|
||||
bool32 OverwriteSavedWonderNewsWithReceivedNews(const struct WonderNews * src)
|
||||
bool32 SaveWonderNews(const struct WonderNews * news)
|
||||
{
|
||||
if (!IsReceivedWonderNewsHeaderValid(src))
|
||||
if (!ValidateWonderNews(news))
|
||||
return FALSE;
|
||||
BlankWonderNews();
|
||||
gSaveBlock1Ptr->mysteryGift.news = *src;
|
||||
gSaveBlock1Ptr->mysteryGift.newsCrc = CalcCRC16WithTable((void *)&gSaveBlock1Ptr->mysteryGift.news, sizeof(struct WonderNews));
|
||||
|
||||
ClearSavedWonderNews();
|
||||
gSaveBlock1Ptr->mysteryGift.news = *news;
|
||||
gSaveBlock1Ptr->mysteryGift.newsCrc = CALC_CRC(gSaveBlock1Ptr->mysteryGift.news);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 ValidateReceivedWonderNews(void)
|
||||
bool32 ValidateSavedWonderNews(void)
|
||||
{
|
||||
if (CalcCRC16WithTable((void *)&gSaveBlock1Ptr->mysteryGift.news, sizeof(struct WonderNews)) != gSaveBlock1Ptr->mysteryGift.newsCrc)
|
||||
if (CALC_CRC(gSaveBlock1Ptr->mysteryGift.news) != gSaveBlock1Ptr->mysteryGift.newsCrc)
|
||||
return FALSE;
|
||||
if (!IsReceivedWonderNewsHeaderValid(&gSaveBlock1Ptr->mysteryGift.news))
|
||||
if (!ValidateWonderNews(&gSaveBlock1Ptr->mysteryGift.news))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool32 IsReceivedWonderNewsHeaderValid(const struct WonderNews * data)
|
||||
static bool32 ValidateWonderNews(const struct WonderNews * news)
|
||||
{
|
||||
if (data->newsId == 0)
|
||||
if (news->id == 0)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 WonderNews_Test_Unk_02(void)
|
||||
bool32 IsSendingSavedWonderNewsAllowed(void)
|
||||
{
|
||||
const struct WonderNews * data = &gSaveBlock1Ptr->mysteryGift.news;
|
||||
if (data->sendType == 0)
|
||||
const struct WonderNews * news = &gSaveBlock1Ptr->mysteryGift.news;
|
||||
if (news->sendType == SEND_TYPE_DISALLOWED)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void BlankWonderNews(void)
|
||||
static void ClearSavedWonderNews(void)
|
||||
{
|
||||
CpuFill32(0, GetSavedWonderNews(), sizeof(gSaveBlock1Ptr->mysteryGift.news));
|
||||
gSaveBlock1Ptr->mysteryGift.newsCrc = 0;
|
||||
}
|
||||
|
||||
static void BlankMENewsJisan(void)
|
||||
static void ClearSavedWonderNewsMetadata(void)
|
||||
{
|
||||
CpuFill32(0, GetMENewsJisanStructPtr(), sizeof(struct WonderNewsMetadata));
|
||||
MENewsJisanReset();
|
||||
CpuFill32(0, GetSavedWonderNewsMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.newsMetadata));
|
||||
WonderNews_Reset();
|
||||
}
|
||||
|
||||
bool32 MEvent_HaveAlreadyReceivedWonderNews(const u8 * src)
|
||||
bool32 IsWonderNewsSameAsSaved(const u8 * news)
|
||||
{
|
||||
const u8 * r5 = (const u8 *)&gSaveBlock1Ptr->mysteryGift.news;
|
||||
const u8 * savedNews = (const u8 *)&gSaveBlock1Ptr->mysteryGift.news;
|
||||
u32 i;
|
||||
if (!ValidateReceivedWonderNews())
|
||||
if (!ValidateSavedWonderNews())
|
||||
return FALSE;
|
||||
for (i = 0; i < sizeof(struct WonderNews); i++)
|
||||
|
||||
for (i = 0; i < sizeof(gSaveBlock1Ptr->mysteryGift.news); i++)
|
||||
{
|
||||
if (r5[i] != src[i])
|
||||
if (savedNews[i] != news[i])
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void DestroyWonderCard(void)
|
||||
void ClearSavedWonderCardAndRelated(void)
|
||||
{
|
||||
BlankSavedWonderCard();
|
||||
BlankMEventBuffer2();
|
||||
BlankBuffer344();
|
||||
ClearSavedWonderCard();
|
||||
ClearSavedWonderCardMetadata();
|
||||
ClearSavedTrainerIds();
|
||||
ClearRamScript();
|
||||
ResetMysteryEventFlags();
|
||||
ResetMysteryEventVars();
|
||||
ClearMysteryGiftFlags();
|
||||
ClearMysteryGiftVars();
|
||||
ClearEReaderTrainer(&gSaveBlock2Ptr->battleTower.ereaderTrainer);
|
||||
}
|
||||
|
||||
bool32 OverwriteSavedWonderCardWithReceivedCard(const struct WonderCard * data)
|
||||
bool32 SaveWonderCard(const struct WonderCard * card)
|
||||
{
|
||||
struct WonderCardMetadata * r2;
|
||||
struct WonderCard * r1;
|
||||
if (!IsReceivedWonderCardHeaderValid(data))
|
||||
struct WonderCardMetadata * metadata;
|
||||
if (!ValidateWonderCard(card))
|
||||
return FALSE;
|
||||
DestroyWonderCard();
|
||||
memcpy(&gSaveBlock1Ptr->mysteryGift.card, data, sizeof(struct WonderCard));
|
||||
gSaveBlock1Ptr->mysteryGift.cardCrc = CalcCRC16WithTable((void *)&gSaveBlock1Ptr->mysteryGift.card, sizeof(struct WonderCard));
|
||||
// Annoying hack to match
|
||||
r2 = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
|
||||
r1 = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
r2->iconSpecies = r1->iconSpecies;
|
||||
|
||||
ClearSavedWonderCardAndRelated();
|
||||
memcpy(&gSaveBlock1Ptr->mysteryGift.card, card, sizeof(struct WonderCard));
|
||||
gSaveBlock1Ptr->mysteryGift.cardCrc = CALC_CRC(gSaveBlock1Ptr->mysteryGift.card);
|
||||
metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
|
||||
metadata->iconSpecies = (&gSaveBlock1Ptr->mysteryGift.card)->iconSpecies;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 ValidateReceivedWonderCard(void)
|
||||
bool32 ValidateSavedWonderCard(void)
|
||||
{
|
||||
if (gSaveBlock1Ptr->mysteryGift.cardCrc != CalcCRC16WithTable((void *)&gSaveBlock1Ptr->mysteryGift.card, sizeof(struct WonderCard)))
|
||||
if (gSaveBlock1Ptr->mysteryGift.cardCrc != CALC_CRC(gSaveBlock1Ptr->mysteryGift.card))
|
||||
return FALSE;
|
||||
if (!IsReceivedWonderCardHeaderValid(&gSaveBlock1Ptr->mysteryGift.card))
|
||||
if (!ValidateWonderCard(&gSaveBlock1Ptr->mysteryGift.card))
|
||||
return FALSE;
|
||||
if (!ValidateRamScript())
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool32 IsReceivedWonderCardHeaderValid(const struct WonderCard * data)
|
||||
static bool32 ValidateWonderCard(const struct WonderCard * card)
|
||||
{
|
||||
if (data->flagId == 0)
|
||||
if (card->flagId == 0)
|
||||
return FALSE;
|
||||
if (data->type > 2)
|
||||
if (card->type >= CARD_TYPE_COUNT)
|
||||
return FALSE;
|
||||
if (!(data->sendType == 0 || data->sendType == 1 || data->sendType == 2))
|
||||
if (!(card->sendType == SEND_TYPE_DISALLOWED
|
||||
|| card->sendType == SEND_TYPE_ALLOWED
|
||||
|| card->sendType == SEND_TYPE_ALLOWED_ALWAYS))
|
||||
return FALSE;
|
||||
if (data->bgType > 7)
|
||||
if (card->bgType >= NUM_WONDER_BGS)
|
||||
return FALSE;
|
||||
if (data->maxStamps > 7)
|
||||
if (card->maxStamps > MAX_STAMP_CARD_STAMPS)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 WonderCard_Test_Unk_08_6(void)
|
||||
bool32 IsSendingSavedWonderCardAllowed(void)
|
||||
{
|
||||
const struct WonderCard * data = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (data->sendType == 0)
|
||||
const struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (card->sendType == SEND_TYPE_DISALLOWED)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void BlankSavedWonderCard(void)
|
||||
static void ClearSavedWonderCard(void)
|
||||
{
|
||||
CpuFill32(0, &gSaveBlock1Ptr->mysteryGift.card, sizeof(struct WonderCard));
|
||||
CpuFill32(0, &gSaveBlock1Ptr->mysteryGift.card, sizeof(gSaveBlock1Ptr->mysteryGift.card));
|
||||
gSaveBlock1Ptr->mysteryGift.cardCrc = 0;
|
||||
}
|
||||
|
||||
static void BlankMEventBuffer2(void)
|
||||
static void ClearSavedWonderCardMetadata(void)
|
||||
{
|
||||
CpuFill32(0, sav1_get_mevent_buffer_2(), 18 * sizeof(u16));
|
||||
CpuFill32(0, GetSavedWonderCardMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.cardMetadata));
|
||||
gSaveBlock1Ptr->mysteryGift.cardMetadataCrc = 0;
|
||||
}
|
||||
|
||||
u16 GetWonderCardFlagId(void)
|
||||
{
|
||||
if (ValidateReceivedWonderCard())
|
||||
if (ValidateSavedWonderCard())
|
||||
return gSaveBlock1Ptr->mysteryGift.card.flagId;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MEvent_WonderCardResetUnk08_6(struct WonderCard * buffer)
|
||||
void DisableWonderCardSending(struct WonderCard * card)
|
||||
{
|
||||
if (buffer->sendType == 1)
|
||||
buffer->sendType = 0;
|
||||
if (card->sendType == SEND_TYPE_ALLOWED)
|
||||
card->sendType = SEND_TYPE_DISALLOWED;
|
||||
}
|
||||
|
||||
static bool32 IsCardIdInValidRange(u16 a0)
|
||||
static bool32 IsWonderCardFlagIDInValidRange(u16 flagId)
|
||||
{
|
||||
if (a0 >= 1000 && a0 < 1020)
|
||||
if (flagId >= WONDER_CARD_FLAG_OFFSET && flagId < WONDER_CARD_FLAG_OFFSET + NUM_WONDER_CARD_FLAGS)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 CheckReceivedGiftFromWonderCard(void)
|
||||
bool32 IsSavedWonderCardGiftNotReceived(void)
|
||||
{
|
||||
u16 value = GetWonderCardFlagId();
|
||||
if (!IsCardIdInValidRange(value))
|
||||
if (!IsWonderCardFlagIDInValidRange(value))
|
||||
return FALSE;
|
||||
if (FlagGet(sGiftItemFlagIds[value - 1000]) == TRUE)
|
||||
|
||||
// If flag is set, player has received gift from this card
|
||||
if (FlagGet(sReceivedGiftFlags[value - WONDER_CARD_FLAG_OFFSET]) == TRUE)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static s32 CountReceivedDistributionMons(const struct WonderCardMetadata * data, s32 size)
|
||||
static s32 GetNumStampsInMetadata(const struct WonderCardMetadata * data, s32 size)
|
||||
{
|
||||
s32 r3 = 0;
|
||||
s32 numStamps = 0;
|
||||
s32 i;
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (data->stampData[1][i] && data->stampData[0][i])
|
||||
r3++;
|
||||
if (data->stampData[STAMP_ID][i] && data->stampData[STAMP_SPECIES][i])
|
||||
numStamps++;
|
||||
}
|
||||
return r3;
|
||||
return numStamps;
|
||||
}
|
||||
|
||||
static bool32 HasPlayerAlreadyReceivedDistributedMon(const struct WonderCardMetadata * data1, const u16 * data2, s32 size)
|
||||
static bool32 IsStampInMetadata(const struct WonderCardMetadata * metadata, const u16 * stamp, s32 maxStamps)
|
||||
{
|
||||
s32 i;
|
||||
for (i = 0; i < size; i++)
|
||||
for (i = 0; i < maxStamps; i++)
|
||||
{
|
||||
if (data1->stampData[1][i] == data2[1])
|
||||
if (metadata->stampData[STAMP_ID][i] == stamp[STAMP_ID])
|
||||
return TRUE;
|
||||
if (data1->stampData[0][i] == data2[0])
|
||||
if (metadata->stampData[STAMP_SPECIES][i] == stamp[STAMP_SPECIES])
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool32 IsWonderCardSpeciesValid(const u16 * data)
|
||||
static bool32 ValidateStamp(const u16 * stamp)
|
||||
{
|
||||
if (data[1] == 0)
|
||||
if (stamp[STAMP_ID] == 0)
|
||||
return FALSE;
|
||||
if (data[0] == SPECIES_NONE)
|
||||
if (stamp[STAMP_SPECIES] == SPECIES_NONE)
|
||||
return FALSE;
|
||||
if (data[0] >= NUM_SPECIES)
|
||||
if (stamp[STAMP_SPECIES] >= NUM_SPECIES)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static s32 ValidateCardAndCountMonsReceived(void)
|
||||
static s32 GetNumStampsInSavedCard(void)
|
||||
{
|
||||
struct WonderCard * data;
|
||||
if (!ValidateReceivedWonderCard())
|
||||
struct WonderCard * card;
|
||||
if (!ValidateSavedWonderCard())
|
||||
return 0;
|
||||
data = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (data->type != 1)
|
||||
card = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (card->type != CARD_TYPE_STAMP)
|
||||
return 0;
|
||||
return CountReceivedDistributionMons(&gSaveBlock1Ptr->mysteryGift.cardMetadata, data->maxStamps);
|
||||
return GetNumStampsInMetadata(&gSaveBlock1Ptr->mysteryGift.cardMetadata, card->maxStamps);
|
||||
}
|
||||
|
||||
bool32 MEvent_ReceiveDistributionMon(const u16 * data)
|
||||
bool32 MysteryGift_TrySaveStamp(const u16 * stamp)
|
||||
{
|
||||
struct WonderCard * buffer = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
s32 capacity = buffer->maxStamps;
|
||||
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
s32 maxStamps = card->maxStamps;
|
||||
s32 i;
|
||||
if (!IsWonderCardSpeciesValid(data))
|
||||
if (!ValidateStamp(stamp))
|
||||
return FALSE;
|
||||
if (HasPlayerAlreadyReceivedDistributedMon(&gSaveBlock1Ptr->mysteryGift.cardMetadata, data, capacity))
|
||||
if (IsStampInMetadata(&gSaveBlock1Ptr->mysteryGift.cardMetadata, stamp, maxStamps))
|
||||
return FALSE;
|
||||
for (i = 0; i < capacity; i++)
|
||||
for (i = 0; i < maxStamps; i++)
|
||||
{
|
||||
if (gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[1][i] == 0 && gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[0][i] == 0)
|
||||
if (gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_ID][i] == 0
|
||||
&& gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_SPECIES][i] == SPECIES_NONE)
|
||||
{
|
||||
gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[1][i] = data[1];
|
||||
gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[0][i] = data[0];
|
||||
gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_ID][i] = stamp[STAMP_ID];
|
||||
gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_SPECIES][i] = stamp[STAMP_SPECIES];
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define GAME_DATA_VALID_VAR 0x101
|
||||
|
||||
#if defined(FIRERED)
|
||||
#define MEVENT_HEADER_VERSION_CODE 1
|
||||
#define VERSION_CODE 1
|
||||
#elif defined(LEAFGREEN)
|
||||
#define MEVENT_HEADER_VERSION_CODE 2
|
||||
#define VERSION_CODE 2
|
||||
#endif
|
||||
|
||||
void BuildMEventClientHeader(struct MEventClientHeaderStruct * data)
|
||||
void MysteryGift_LoadLinkGameData(struct MysteryGiftLinkGameData * data)
|
||||
{
|
||||
s32 i;
|
||||
CpuFill32(0, data, sizeof(struct MEventClientHeaderStruct));
|
||||
CpuFill32(0, data, sizeof(*data));
|
||||
// Magic
|
||||
data->unk_00 = 0x101;
|
||||
data->unk_00 = GAME_DATA_VALID_VAR;
|
||||
data->unk_04 = 1;
|
||||
data->unk_08 = 1;
|
||||
data->unk_0C = 1;
|
||||
data->unk_10 = MEVENT_HEADER_VERSION_CODE;
|
||||
data->unk_10 = VERSION_CODE;
|
||||
|
||||
// Check whether a card already exists
|
||||
if (ValidateReceivedWonderCard())
|
||||
if (ValidateSavedWonderCard())
|
||||
{
|
||||
// Populate fields
|
||||
data->id = GetSavedWonderCard()->flagId;
|
||||
data->unk_20 = *sav1_get_mevent_buffer_2();
|
||||
data->maxDistributionMons = GetSavedWonderCard()->maxStamps;
|
||||
data->flagId = GetSavedWonderCard()->flagId;
|
||||
data->cardMetadata = *GetSavedWonderCardMetadata();
|
||||
data->maxStamps = GetSavedWonderCard()->maxStamps;
|
||||
}
|
||||
else
|
||||
data->id = 0;
|
||||
{
|
||||
data->flagId = 0;
|
||||
}
|
||||
|
||||
// Get something
|
||||
for (i = 0; i < 4; i++)
|
||||
data->unk_16[i] = gSaveBlock1Ptr->mysteryGift.questionnaireWords[i];
|
||||
for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++)
|
||||
data->questionnaireWords[i] = gSaveBlock1Ptr->mysteryGift.questionnaireWords[i];
|
||||
|
||||
// Get player ID
|
||||
CopyTrainerId(data->playerTrainerId, gSaveBlock2Ptr->playerTrainerId);
|
||||
StringCopy(data->playerName, gSaveBlock2Ptr->playerName);
|
||||
for (i = 0; i < 6; i++)
|
||||
for (i = 0; i < EASY_CHAT_BATTLE_WORDS_COUNT; i++)
|
||||
data->easyChatProfile[i] = gSaveBlock1Ptr->easyChatProfile[i];
|
||||
memcpy(data->gameCode, RomHeaderGameCode, 4);
|
||||
|
||||
memcpy(data->gameCode, RomHeaderGameCode, GAME_CODE_LENGTH);
|
||||
data->version = RomHeaderSoftwareVersion;
|
||||
}
|
||||
|
||||
bool32 ValidateMEventClientHeader(const struct MEventClientHeaderStruct * data)
|
||||
bool32 MysteryGift_ValidateLinkGameData(const struct MysteryGiftLinkGameData * data)
|
||||
{
|
||||
if (data->unk_00 != 0x101)
|
||||
if (data->unk_00 != GAME_DATA_VALID_VAR)
|
||||
return FALSE;
|
||||
if (!(data->unk_04 & 1))
|
||||
return FALSE;
|
||||
@@ -799,145 +810,156 @@ bool32 ValidateMEventClientHeader(const struct MEventClientHeaderStruct * data)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u32 sub_8144418(const u16 * a0, const struct MEventClientHeaderStruct * a1, void *unused)
|
||||
u32 MysteryGift_CompareCardFlags(const u16 * flagId, const struct MysteryGiftLinkGameData * data, void *unused)
|
||||
{
|
||||
if (a1->id == 0)
|
||||
// Has a Wonder Card already?
|
||||
if (data->flagId == 0)
|
||||
return 0;
|
||||
if (*a0 == a1->id)
|
||||
|
||||
// Has this Wonder Card already?
|
||||
if (*flagId == data->flagId)
|
||||
return 1;
|
||||
|
||||
// Player has a different Wonder Card
|
||||
return 2;
|
||||
}
|
||||
|
||||
u32 MEvent_CanPlayerReceiveDistributionMon(const u16 * a0, const struct MEventClientHeaderStruct * a1, void *unused)
|
||||
u32 MysteryGift_CheckStamps(const u16 * stamp, const struct MysteryGiftLinkGameData * data, void *unused)
|
||||
{
|
||||
s32 numSpaces = a1->maxDistributionMons - CountReceivedDistributionMons(&a1->unk_20, a1->maxDistributionMons);
|
||||
if (numSpaces == 0)
|
||||
s32 stampsMissing = data->maxStamps - GetNumStampsInMetadata(&data->cardMetadata, data->maxStamps);
|
||||
|
||||
// Has full stamp card?
|
||||
if (stampsMissing == 0)
|
||||
return 1;
|
||||
if (HasPlayerAlreadyReceivedDistributedMon(&a1->unk_20, a0, a1->maxDistributionMons))
|
||||
|
||||
// Already has stamp?
|
||||
if (IsStampInMetadata(&data->cardMetadata, stamp, data->maxStamps))
|
||||
return 3;
|
||||
if (numSpaces == 1)
|
||||
|
||||
// Only 1 empty stamp left?
|
||||
if (stampsMissing == 1)
|
||||
return 4;
|
||||
|
||||
// This is a new stamp
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool32 sub_8144474(const struct MEventClientHeaderStruct * a0, const u16 * a1)
|
||||
bool32 MysteryGift_DoesQuestionnaireMatch(const struct MysteryGiftLinkGameData * data, const u16 * words)
|
||||
{
|
||||
s32 i;
|
||||
for (i = 0; i < 4; i++)
|
||||
for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++)
|
||||
{
|
||||
if (a0->unk_16[i] != a1[i])
|
||||
if (data->questionnaireWords[i] != words[i])
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static s32 GetNumReceivedDistributionMons(const struct MEventClientHeaderStruct * a0)
|
||||
static s32 GetNumStampsInLinkData(const struct MysteryGiftLinkGameData * data)
|
||||
{
|
||||
return CountReceivedDistributionMons(&a0->unk_20, a0->maxDistributionMons);
|
||||
return GetNumStampsInMetadata(&data->cardMetadata, data->maxStamps);
|
||||
}
|
||||
|
||||
u16 sub_81444B0(const struct MEventClientHeaderStruct * a0, u32 command)
|
||||
u16 MysteryGift_GetCardStatFromLinkData(const struct MysteryGiftLinkGameData * data, u32 stat)
|
||||
{
|
||||
switch (command)
|
||||
switch (stat)
|
||||
{
|
||||
case 0:
|
||||
return a0->unk_20.battlesWon;
|
||||
case 1:
|
||||
return a0->unk_20.battlesLost;
|
||||
case 2:
|
||||
return a0->unk_20.numTrades;
|
||||
case 3:
|
||||
return GetNumReceivedDistributionMons(a0);
|
||||
case 4:
|
||||
return a0->maxDistributionMons;
|
||||
default:
|
||||
AGB_ASSERT_EX(0, ABSPATH("mevent.c"), 825);
|
||||
return 0;
|
||||
case CARD_STAT_BATTLES_WON:
|
||||
return data->cardMetadata.battlesWon;
|
||||
case CARD_STAT_BATTLES_LOST:
|
||||
return data->cardMetadata.battlesLost;
|
||||
case CARD_STAT_NUM_TRADES:
|
||||
return data->cardMetadata.numTrades;
|
||||
case CARD_STAT_NUM_STAMPS:
|
||||
return GetNumStampsInLinkData(data);
|
||||
case CARD_STAT_MAX_STAMPS:
|
||||
return data->maxStamps;
|
||||
default:
|
||||
AGB_ASSERT_EX(0, ABSPATH("mevent.c"), 825);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Increments an interaction count in the save block
|
||||
static void IncrementBattleCardCount(u32 command)
|
||||
static void IncrementCardStat(u32 statType)
|
||||
{
|
||||
struct WonderCard * data = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (data->type == 2)
|
||||
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (card->type == CARD_TYPE_LINK_STAT)
|
||||
{
|
||||
u16 * dest = NULL;
|
||||
switch (command)
|
||||
u16 * stat = NULL;
|
||||
switch (statType)
|
||||
{
|
||||
case 0:
|
||||
dest = &gSaveBlock1Ptr->mysteryGift.cardMetadata.battlesWon;
|
||||
break;
|
||||
case 1:
|
||||
dest = &gSaveBlock1Ptr->mysteryGift.cardMetadata.battlesLost;
|
||||
break;
|
||||
case 2:
|
||||
dest = &gSaveBlock1Ptr->mysteryGift.cardMetadata.numTrades;
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
case CARD_STAT_BATTLES_WON:
|
||||
stat = &gSaveBlock1Ptr->mysteryGift.cardMetadata.battlesWon;
|
||||
break;
|
||||
case CARD_STAT_BATTLES_LOST:
|
||||
stat = &gSaveBlock1Ptr->mysteryGift.cardMetadata.battlesLost;
|
||||
break;
|
||||
case CARD_STAT_NUM_TRADES:
|
||||
stat = &gSaveBlock1Ptr->mysteryGift.cardMetadata.numTrades;
|
||||
break;
|
||||
case CARD_STAT_NUM_STAMPS:
|
||||
case CARD_STAT_MAX_STAMPS:
|
||||
break;
|
||||
}
|
||||
if (dest == NULL)
|
||||
if (stat == NULL)
|
||||
{
|
||||
AGB_ASSERT_EX(0, ABSPATH("mevent.c"), 868);
|
||||
}
|
||||
else if (++(*dest) > 999)
|
||||
else if (++(*stat) > MAX_WONDER_CARD_STAT)
|
||||
{
|
||||
*dest = 999;
|
||||
*stat = MAX_WONDER_CARD_STAT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u16 MEvent_GetBattleCardCount(u32 command)
|
||||
u16 MysteryGift_GetCardStat(u32 stat)
|
||||
{
|
||||
switch (command)
|
||||
switch (stat)
|
||||
{
|
||||
case 0:
|
||||
case CARD_STAT_BATTLES_WON:
|
||||
{
|
||||
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (card->type == CARD_TYPE_LINK_STAT)
|
||||
{
|
||||
struct WonderCard * data = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (data->type == 2)
|
||||
{
|
||||
struct WonderCardMetadata * buffer = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
|
||||
return buffer->battlesWon;
|
||||
}
|
||||
break;
|
||||
struct WonderCardMetadata * metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
|
||||
return metadata->battlesWon;
|
||||
}
|
||||
case 1:
|
||||
break;
|
||||
}
|
||||
case CARD_STAT_BATTLES_LOST:
|
||||
{
|
||||
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (card->type == CARD_TYPE_LINK_STAT)
|
||||
{
|
||||
struct WonderCard * data = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (data->type == 2)
|
||||
{
|
||||
struct WonderCardMetadata * buffer = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
|
||||
return buffer->battlesLost;
|
||||
}
|
||||
break;
|
||||
struct WonderCardMetadata * metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
|
||||
return metadata->battlesLost;
|
||||
}
|
||||
case 2:
|
||||
break;
|
||||
}
|
||||
case CARD_STAT_NUM_TRADES:
|
||||
{
|
||||
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (card->type == CARD_TYPE_LINK_STAT)
|
||||
{
|
||||
struct WonderCard * data = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (data->type == 2)
|
||||
{
|
||||
struct WonderCardMetadata * buffer = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
|
||||
return buffer->numTrades;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
struct WonderCard * data = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (data->type == 1)
|
||||
return ValidateCardAndCountMonsReceived();
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
struct WonderCard * data = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (data->type == 1)
|
||||
return data->maxStamps;
|
||||
break;
|
||||
struct WonderCardMetadata * metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
|
||||
return metadata->numTrades;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARD_STAT_NUM_STAMPS:
|
||||
{
|
||||
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (card->type == CARD_TYPE_STAMP)
|
||||
return GetNumStampsInSavedCard();
|
||||
break;
|
||||
}
|
||||
case CARD_STAT_MAX_STAMPS:
|
||||
{
|
||||
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
|
||||
if (card->type == CARD_TYPE_STAMP)
|
||||
return card->maxStamps;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AGB_ASSERT_EX(0, ABSPATH("mevent.c"), 913);
|
||||
return 0;
|
||||
@@ -945,85 +967,93 @@ u16 MEvent_GetBattleCardCount(u32 command)
|
||||
|
||||
void MysteryGift_DisableStats(void)
|
||||
{
|
||||
sReceivedWonderCardIsValid = FALSE;
|
||||
sStatsEnabled = FALSE;
|
||||
}
|
||||
|
||||
bool32 MysteryGift_TryEnableStatsByFlagId(u16 flagId)
|
||||
{
|
||||
sReceivedWonderCardIsValid = FALSE;
|
||||
sStatsEnabled = FALSE;
|
||||
if (flagId == 0)
|
||||
return FALSE;
|
||||
if (!ValidateReceivedWonderCard())
|
||||
if (!ValidateSavedWonderCard())
|
||||
return FALSE;
|
||||
if (gSaveBlock1Ptr->mysteryGift.card.flagId != flagId)
|
||||
return FALSE;
|
||||
sReceivedWonderCardIsValid = TRUE;
|
||||
sStatsEnabled = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void MysteryGift_TryIncrementStat(u32 eventId, u32 trainerId)
|
||||
void MysteryGift_TryIncrementStat(u32 stat, u32 trainerId)
|
||||
{
|
||||
if (sReceivedWonderCardIsValid)
|
||||
if (sStatsEnabled)
|
||||
{
|
||||
switch (eventId)
|
||||
switch (stat)
|
||||
{
|
||||
case 2: // trade
|
||||
RecordIdOfWonderCardSender(2, trainerId, gSaveBlock1Ptr->mysteryGift.trainerIds[1], 5);
|
||||
break;
|
||||
case 0: // link win
|
||||
RecordIdOfWonderCardSender(0, trainerId, gSaveBlock1Ptr->mysteryGift.trainerIds[0], 5);
|
||||
break;
|
||||
case 1: // link loss
|
||||
RecordIdOfWonderCardSender(1, trainerId, gSaveBlock1Ptr->mysteryGift.trainerIds[0], 5);
|
||||
break;
|
||||
default:
|
||||
AGB_ASSERT_EX(0, ABSPATH("mevent.c"), 988);
|
||||
case CARD_STAT_NUM_TRADES:
|
||||
IncrementCardStatForNewTrainer(CARD_STAT_NUM_TRADES,
|
||||
trainerId,
|
||||
gSaveBlock1Ptr->mysteryGift.trainerIds[1],
|
||||
ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[1]));
|
||||
break;
|
||||
case CARD_STAT_BATTLES_WON:
|
||||
IncrementCardStatForNewTrainer(CARD_STAT_BATTLES_WON,
|
||||
trainerId,
|
||||
gSaveBlock1Ptr->mysteryGift.trainerIds[0],
|
||||
ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[0]));
|
||||
break;
|
||||
case CARD_STAT_BATTLES_LOST:
|
||||
IncrementCardStatForNewTrainer(CARD_STAT_BATTLES_LOST,
|
||||
trainerId,
|
||||
gSaveBlock1Ptr->mysteryGift.trainerIds[0],
|
||||
ARRAY_COUNT(gSaveBlock1Ptr->mysteryGift.trainerIds[0]));
|
||||
break;
|
||||
default:
|
||||
AGB_ASSERT_EX(0, ABSPATH("mevent.c"), 988);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void BlankBuffer344(void)
|
||||
static void ClearSavedTrainerIds(void)
|
||||
{
|
||||
CpuFill32(0, gSaveBlock1Ptr->mysteryGift.trainerIds, sizeof(gSaveBlock1Ptr->mysteryGift.trainerIds));
|
||||
}
|
||||
|
||||
// Looks up trainerId in an array idsList with count elements.
|
||||
// If trainerId is found, rearranges idsList to put it in the front.
|
||||
// Otherwise, drops the last element of the list and inserts
|
||||
// trainerId at the front.
|
||||
// Returns TRUE in the latter case.
|
||||
static bool32 PlaceTrainerIdAtFrontOfList(u32 trainerId, u32 * idsList, s32 count)
|
||||
// Returns TRUE if it's a new trainer id, FALSE if an existing one.
|
||||
// In either case the given trainerId is saved in element 0
|
||||
static bool32 RecordTrainerId(u32 trainerId, u32 * trainerIds, s32 size)
|
||||
{
|
||||
s32 i;
|
||||
s32 j;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (idsList[i] == trainerId)
|
||||
if (trainerIds[i] == trainerId)
|
||||
break;
|
||||
}
|
||||
if (i == count)
|
||||
|
||||
if (i == size)
|
||||
{
|
||||
for (j = count - 1; j > 0; j--)
|
||||
{
|
||||
idsList[j] = idsList[j - 1];
|
||||
}
|
||||
idsList[0] = trainerId;
|
||||
// New trainer, shift array and insert new id at front
|
||||
for (j = size - 1; j > 0; j--)
|
||||
trainerIds[j] = trainerIds[j - 1];
|
||||
|
||||
trainerIds[0] = trainerId;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Existing trainer, shift back to old slot and move id to front
|
||||
for (j = i; j > 0; j--)
|
||||
{
|
||||
idsList[j] = idsList[j - 1];
|
||||
}
|
||||
idsList[0] = trainerId;
|
||||
trainerIds[j] = trainerIds[j - 1];
|
||||
|
||||
trainerIds[0] = trainerId;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void RecordIdOfWonderCardSender(u32 eventId, u32 trainerId, u32 * idsList, s32 count)
|
||||
static void IncrementCardStatForNewTrainer(u32 stat, u32 trainerId, u32 * trainerIds, s32 size)
|
||||
{
|
||||
if (PlaceTrainerIdAtFrontOfList(trainerId, idsList, count))
|
||||
IncrementBattleCardCount(eventId);
|
||||
if (RecordTrainerId(trainerId, trainerIds, size))
|
||||
IncrementCardStat(stat);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user