Merge branch 'master' into sync-text

This commit is contained in:
GriffinR
2022-11-26 18:08:49 -05:00
committed by GitHub
67 changed files with 3835 additions and 3431 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
#include "link.h"
#include "load_save.h"
#include "m4a.h"
#include "mevent.h"
#include "mystery_gift.h"
#include "new_menu_helpers.h"
#include "overworld.h"
#include "quest_log.h"
+4 -4
View File
@@ -4,7 +4,7 @@
#include "easy_chat.h"
#include "event_data.h"
#include "field_message_box.h"
#include "mevent.h"
#include "mystery_gift.h"
#include "menu.h"
#include "mail.h"
#include "pokedex.h"
@@ -472,11 +472,11 @@ void InitEasyChatPhrases(void)
#endif
}
void EC_ResetMEventProfileMaybe(void)
void InitQuestionnaireWords(void)
{
s32 i;
u16 *ptr = GetMEventProfileECWordsMaybe();
for (i = 0; i < 4; i++)
u16 *ptr = GetQuestionnaireWordsPtr();
for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++)
ptr[i] = EC_WORD_UNDEFINED;
}
+2 -2
View File
@@ -3,7 +3,7 @@
#include "easy_chat.h"
#include "event_data.h"
#include "menu.h"
#include "mevent.h"
#include "mystery_gift.h"
#include "overworld.h"
#include "strings.h"
#include "task.h"
@@ -271,7 +271,7 @@ void ShowEasyChatScreen(void)
words = gSaveBlock1Ptr->easyChatBattleLost;
break;
case EASY_CHAT_TYPE_QUESTIONNAIRE:
words = GetMEventProfileECWordsMaybe();
words = GetQuestionnaireWordsPtr();
break;
case EASY_CHAT_TYPE_MAIL:
words = gSaveBlock1Ptr->mail[gSpecialVar_0x8005].words;
+520
View File
@@ -0,0 +1,520 @@
#include "global.h"
#include "malloc.h"
#include "decompress.h"
#include "ereader_helpers.h"
#include "link.h"
#include "main.h"
#include "mystery_gift_menu.h"
#include "mystery_gift_client.h"
#include "save.h"
#include "sound.h"
#include "sprite.h"
#include "task.h"
#include "strings.h"
#include "util.h"
#include "cereader_tool.h"
#include "help_system.h"
#include "constants/songs.h"
struct EReaderTaskData
{
u16 timer;
u16 unused1;
u16 unused2;
u16 unused3;
u8 state;
u8 textState;
u8 unused4;
u8 unused5;
u8 unused6;
u8 unused7;
u8 status;
u8 *unusedBuffer;
};
struct EReaderData
{
u16 status;
size_t size;
const void *data;
};
static void Task_EReader(u8);
struct EReaderData gEReaderData;
extern const u8 gMultiBootProgram_EReader_Start[];
extern const u8 gMultiBootProgram_EReader_End[];
static void EReader_Load(struct EReaderData *eReader, size_t size, const void *data)
{
vu16 imeBak = REG_IME;
REG_IME = 0;
gIntrTable[1] = EReaderHelper_SerialCallback;
gIntrTable[2] = EReaderHelper_Timer3Callback;
EReaderHelper_SaveRegsState();
EReaderHelper_ClearsSendRecvMgr();
REG_IE |= INTR_FLAG_VCOUNT;
REG_IME = imeBak;
eReader->status = 0;
eReader->size = size;
eReader->data = data;
}
static void EReader_Reset(struct EReaderData *eReader)
{
vu16 imeBak = REG_IME;
REG_IME = 0;
EReaderHelper_ClearsSendRecvMgr();
EReaderHelper_RestoreRegsState();
RestoreSerialTimer3IntrHandlers();
REG_IME = imeBak;
}
// Return values for EReader_Transfer
enum {
TRANSFER_ACTIVE,
TRANSFER_SUCCESS,
TRANSFER_CANCELED,
TRANSFER_TIMEOUT,
};
static u8 EReader_Transfer(struct EReaderData *eReader)
{
u8 transferStatus = TRANSFER_ACTIVE;
eReader->status = EReaderHandleTransfer(TRUE, eReader->size, eReader->data, NULL);
if ((eReader->status & EREADER_XFER_MASK) == 0 && eReader->status & EREADER_CHECKSUM_OK_MASK)
transferStatus = TRANSFER_SUCCESS;
if (eReader->status & EREADER_CANCEL_KEY_MASK)
transferStatus = TRANSFER_CANCELED;
if (eReader->status & EREADER_CANCEL_TIMEOUT_MASK)
transferStatus = TRANSFER_TIMEOUT;
gShouldAdvanceLinkState = 0;
return transferStatus;
}
static void OpenEReaderLink(void)
{
memset(gDecompressionBuffer, 0, 0x2000);
gLinkType = LINKTYPE_EREADER_FRLG;
OpenLink();
SetSuppressLinkErrorMessage(TRUE);
}
static bool32 ValidateEReaderConnection(void)
{
vu16 imeBak = REG_IME;
u16 handshakes[MAX_LINK_PLAYERS];
REG_IME = 0;
*(u64 *)handshakes = *(u64 *)gLink.tempRecvBuffer;
REG_IME = imeBak;
// Validate that we are player 1, the EReader is player 2,
// and that players 3 and 4 are empty.
if (handshakes[0] == SLAVE_HANDSHAKE
&& handshakes[1] == EREADER_HANDSHAKE
&& handshakes[2] == 0xFFFF
&& handshakes[3] == 0xFFFF)
return TRUE;
return FALSE;
}
static bool32 IsEReaderConnectionSane(void)
{
if (IsLinkMaster() && GetLinkPlayerCount_2() == 2)
return TRUE;
return FALSE;
}
// States for TryReceiveCard
enum {
RECV_STATE_INIT,
RECV_STATE_WAIT_START,
RECV_STATE_START,
RECV_STATE_EXCHANGE,
RECV_STATE_START_DISCONNECT,
RECV_STATE_WAIT_DISCONNECT,
};
// Return values for TryReceiveCard
enum {
RECV_ACTIVE,
RECV_CANCELED,
RECV_SUCCESS,
RECV_ERROR,
RECV_DISCONNECTED,
RECV_TIMEOUT,
};
static u32 TryReceiveCard(u8 * state, u16 * timer)
{
if ((*state == RECV_STATE_EXCHANGE
|| *state == RECV_STATE_START_DISCONNECT
|| *state == RECV_STATE_WAIT_DISCONNECT)
&& HasLinkErrorOccurred())
{
// Return error status if an error occurs
// during the link exchange.
*state = 0;
return RECV_ERROR;
}
switch (*state)
{
case RECV_STATE_INIT:
if (IsLinkMaster() && GetLinkPlayerCount_2() > 1)
{
*state = RECV_STATE_WAIT_START;
}
else if (JOY_NEW(B_BUTTON))
{
*state = 0;
return RECV_CANCELED;
}
break;
case RECV_STATE_WAIT_START:
if (++(*timer) > 5)
{
*timer = 0;
*state = RECV_STATE_START;
}
break;
case RECV_STATE_START:
if (GetLinkPlayerCount_2() == 2)
{
PlaySE(SE_DING_DONG);
CheckShouldAdvanceLinkState();
*timer = 0;
*state = RECV_STATE_EXCHANGE;
}
else if (JOY_NEW(B_BUTTON))
{
*state = 0;
return RECV_CANCELED;
}
break;
case RECV_STATE_EXCHANGE:
if (++(*timer) > 30)
{
*state = 0;
return RECV_TIMEOUT;
}
if (IsLinkConnectionEstablished())
{
if (gReceivedRemoteLinkPlayers)
{
if (IsLinkPlayerDataExchangeComplete())
{
*state = 0;
return RECV_SUCCESS;
}
else
*state = RECV_STATE_START_DISCONNECT;
}
else
*state = RECV_STATE_EXCHANGE;
}
break;
case RECV_STATE_START_DISCONNECT:
SetCloseLinkCallbackAndType(0);
*state = RECV_STATE_WAIT_DISCONNECT;
break;
case RECV_STATE_WAIT_DISCONNECT:
if (!gReceivedRemoteLinkPlayers)
{
*state = 0;
return RECV_DISCONNECTED;
}
break;
}
return RECV_ACTIVE;
}
void CreateEReaderTask(void)
{
u8 taskId = CreateTask(Task_EReader, 0);
struct EReaderTaskData *data = (struct EReaderTaskData *)gTasks[taskId].data;
data->state = 0;
data->textState = 0;
data->unused4 = 0;
data->unused5 = 0;
data->unused6 = 0;
data->unused7 = 0;
data->timer = 0;
data->unused1 = 0;
data->unused2 = 0;
data->unused3 = 0;
data->status = 0;
data->unusedBuffer = AllocZeroed(CLIENT_MAX_MSG_SIZE);
}
static void ResetTimer(u16 *timer)
{
*timer = 0;
}
static bool32 UpdateTimer(u16 * timer, u16 time)
{
if (++(*timer) > time)
{
// Timer has finished
*timer = 0;
return TRUE;
}
return FALSE;
}
// States for Task_EReader
enum {
ER_STATE_START,
ER_STATE_INIT_LINK,
ER_STATE_INIT_LINK_WAIT,
ER_STATE_INIT_LINK_CHECK,
ER_STATE_MSG_SELECT_CONNECT,
ER_STATE_MSG_SELECT_CONNECT_WAIT,
ER_STATE_TRY_LINK,
ER_STATE_INCORRECT_LINK,
ER_STATE_CONNECTING,
ER_STATE_TRANSFER,
ER_STATE_TRANSFER_END,
ER_STATE_TRANSFER_SUCCESS,
ER_STATE_LOAD_CARD_START,
ER_STATE_LOAD_CARD,
ER_STATE_WAIT_RECV_CARD,
ER_STATE_VALIDATE_CARD,
ER_STATE_WAIT_DISCONNECT,
ER_STATE_SAVE,
ER_STATE_SUCCESS_MSG,
ER_STATE_SUCCESS_END,
ER_STATE_LINK_ERROR,
ER_STATE_LINK_ERROR_TRY_AGAIN,
ER_STATE_SAVE_FAILED,
ER_STATE_CANCELED_CARD_READ,
ER_STATE_UNUSED_1,
ER_STATE_UNUSED_2,
ER_STATE_END,
};
static void Task_EReader(u8 taskId)
{
struct EReaderTaskData *data = (struct EReaderTaskData *)gTasks[taskId].data;
switch (data->state)
{
case ER_STATE_START:
if (PrintMysteryGiftMenuMessage(&data->textState, gJPText_ReceiveMysteryGiftWithEReader))
data->state = ER_STATE_INIT_LINK;
break;
case ER_STATE_INIT_LINK:
OpenEReaderLink();
ResetTimer(&data->timer);
data->state = ER_STATE_INIT_LINK_WAIT;
break;
case ER_STATE_INIT_LINK_WAIT:
if (UpdateTimer(&data->timer, 10))
data->state = ER_STATE_INIT_LINK_CHECK;
break;
case ER_STATE_INIT_LINK_CHECK:
if (!IsEReaderConnectionSane())
{
CloseLink();
data->state = ER_STATE_MSG_SELECT_CONNECT;
}
else
data->state = ER_STATE_LOAD_CARD;
break;
case ER_STATE_MSG_SELECT_CONNECT:
if (PrintMysteryGiftMenuMessage(&data->textState, gJPText_SelectConnectFromEReaderMenu))
{
AddTextPrinterToWindow1(gJPText_SelectConnectWithGBA);
ResetTimer(&data->timer);
data->state = ER_STATE_MSG_SELECT_CONNECT_WAIT;
}
break;
case ER_STATE_MSG_SELECT_CONNECT_WAIT:
if (UpdateTimer(&data->timer, 90))
{
OpenEReaderLink();
data->state = ER_STATE_TRY_LINK;
}
else if (JOY_NEW(B_BUTTON))
{
ResetTimer(&data->timer);
PlaySE(SE_SELECT);
data->state = ER_STATE_CANCELED_CARD_READ;
}
break;
case ER_STATE_TRY_LINK:
if (JOY_NEW(B_BUTTON))
{
// Canceled
PlaySE(SE_SELECT);
CloseLink();
ResetTimer(&data->timer);
data->state = ER_STATE_CANCELED_CARD_READ;
}
else if (GetLinkPlayerCount_2() > 1)
{
ResetTimer(&data->timer);
CloseLink();
data->state = ER_STATE_INCORRECT_LINK;
}
else if (ValidateEReaderConnection())
{
// Successful connection
PlaySE(SE_SELECT);
CloseLink();
ResetTimer(&data->timer);
data->state = ER_STATE_CONNECTING;
}
else if (UpdateTimer(&data->timer, 10))
{
// Retry connection
CloseLink();
OpenEReaderLink();
ResetTimer(&data->timer);
}
break;
case ER_STATE_INCORRECT_LINK:
if (PrintMysteryGiftMenuMessage(&data->textState, gJPText_LinkIsIncorrect))
data->state = ER_STATE_MSG_SELECT_CONNECT;
break;
case ER_STATE_CONNECTING:
AddTextPrinterToWindow1(gJPText_Connecting);
EReader_Load(&gEReaderData, gMultiBootProgram_EReader_End - gMultiBootProgram_EReader_Start, gMultiBootProgram_EReader_Start);
data->state = ER_STATE_TRANSFER;
break;
case ER_STATE_TRANSFER:
data->status = EReader_Transfer(&gEReaderData);
if (data->status != TRANSFER_ACTIVE)
data->state = ER_STATE_TRANSFER_END;
break;
case ER_STATE_TRANSFER_END:
EReader_Reset(&gEReaderData);
if (data->status == TRANSFER_TIMEOUT)
{
data->state = ER_STATE_LINK_ERROR;
}
else if (data->status == TRANSFER_SUCCESS)
{
ResetTimer(&data->timer);
AddTextPrinterToWindow1(gJPText_PleaseWaitAMoment);
data->state = ER_STATE_TRANSFER_SUCCESS;
}
else // TRANSFER_CANCELED
{
data->state = ER_STATE_START;
}
break;
case ER_STATE_TRANSFER_SUCCESS:
if (UpdateTimer(&data->timer, 840))
data->state = ER_STATE_LOAD_CARD_START;
break;
case ER_STATE_LOAD_CARD_START:
OpenEReaderLink();
AddTextPrinterToWindow1(gJPText_AllowEReaderToLoadCard);
data->state = ER_STATE_LOAD_CARD;
break;
case ER_STATE_LOAD_CARD:
switch (TryReceiveCard(&data->textState, &data->timer))
{
case RECV_ACTIVE:
// Running
break;
case RECV_SUCCESS:
AddTextPrinterToWindow1(gJPText_Connecting);
data->state = ER_STATE_WAIT_RECV_CARD;
break;
case RECV_CANCELED:
PlaySE(SE_SELECT);
CloseLink();
data->state = ER_STATE_CANCELED_CARD_READ;
break;
case RECV_TIMEOUT:
CloseLink();
data->state = ER_STATE_LINK_ERROR_TRY_AGAIN;
break;
case RECV_ERROR:
case RECV_DISCONNECTED:
CloseLink();
data->state = ER_STATE_LINK_ERROR;
break;
}
break;
case ER_STATE_WAIT_RECV_CARD:
if (HasLinkErrorOccurred())
{
CloseLink();
data->state = ER_STATE_LINK_ERROR;
}
else if (GetBlockReceivedStatus())
{
ResetBlockReceivedFlags();
data->state = ER_STATE_VALIDATE_CARD;
}
break;
case ER_STATE_VALIDATE_CARD:
data->status = ValidateTrainerTowerData((struct EReaderTrainerTowerSet *)gDecompressionBuffer);
SetCloseLinkCallbackAndType(data->status);
data->state = ER_STATE_WAIT_DISCONNECT;
break;
case ER_STATE_WAIT_DISCONNECT:
if (!gReceivedRemoteLinkPlayers)
{
if (data->status == TRUE) // Was data valid?
data->state = ER_STATE_SAVE;
else
data->state = ER_STATE_LINK_ERROR;
}
break;
case ER_STATE_SAVE:
if (CEReaderTool_SaveTrainerTower((struct EReaderTrainerTowerSet *)gDecompressionBuffer))
{
AddTextPrinterToWindow1(gJPText_ConnectionComplete);
ResetTimer(&data->timer);
data->state = ER_STATE_SUCCESS_MSG;
}
else
data->state = ER_STATE_SAVE_FAILED;
break;
case ER_STATE_SUCCESS_MSG:
if (UpdateTimer(&data->timer, 120))
{
AddTextPrinterToWindow1(gJPText_NewTrainerHasComeToSevii);
PlayFanfare(MUS_OBTAIN_ITEM);
data->state = ER_STATE_SUCCESS_END;
}
break;
case ER_STATE_SUCCESS_END:
if (IsFanfareTaskInactive() && JOY_NEW(A_BUTTON | B_BUTTON))
data->state = ER_STATE_END;
break;
case ER_STATE_CANCELED_CARD_READ:
if (PrintMysteryGiftMenuMessage(&data->textState, gJPText_CardReadingHasBeenHalted))
data->state = ER_STATE_END;
break;
case ER_STATE_LINK_ERROR:
if (PrintMysteryGiftMenuMessage(&data->textState, gJPText_ConnectionErrorCheckLink))
data->state = ER_STATE_START;
break;
case ER_STATE_LINK_ERROR_TRY_AGAIN:
if (PrintMysteryGiftMenuMessage(&data->textState, gJPText_ConnectionErrorTryAgain))
data->state = ER_STATE_START;
break;
case ER_STATE_SAVE_FAILED:
if (PrintMysteryGiftMenuMessage(&data->textState, gJPText_WriteErrorUnableToSaveData))
data->state = ER_STATE_START;
break;
case ER_STATE_END:
HelpSystem_Enable();
Free(data->unusedBuffer);
DestroyTask(taskId);
SetMainCallback2(MainCB_FreeAllBuffersAndReturnToInitTitleScreen);
break;
}
}
+2 -2
View File
@@ -129,7 +129,7 @@ bool32 IsMysteryGiftEnabled(void)
return FlagGet(FLAG_SYS_MYSTERY_GIFT_ENABLED);
}
void ResetMysteryEventFlags(void)
void ClearMysteryGiftFlags(void)
{
FlagClear(FLAG_MYSTERY_GIFT_DONE);
FlagClear(FLAG_MYSTERY_GIFT_1);
@@ -149,7 +149,7 @@ void ResetMysteryEventFlags(void)
FlagClear(FLAG_MYSTERY_GIFT_15);
}
void ResetMysteryEventVars(void)
void ClearMysteryGiftVars(void)
{
VarSet(VAR_EVENT_PICHU_SLOT, 0);
VarSet(VAR_MYSTERY_GIFT_1, 0);
+2 -2
View File
@@ -14,7 +14,7 @@
#include "field_specials.h"
#include "item_menu.h"
#include "link.h"
#include "menews_jisan.h"
#include "wonder_news.h"
#include "metatile_behavior.h"
#include "overworld.h"
#include "renewable_hidden_items.h"
@@ -215,7 +215,7 @@ int ProcessPlayerFieldInput(struct FieldInput *input)
if (input->tookStep)
{
IncrementGameStat(GAME_STAT_STEPS);
MENewsJisanStepCounter();
WonderNews_IncrementStepCounter();
IncrementRenewableHiddenItemStepCounter();
RunMassageCooldownStepCounter();
IncrementResortGorgeousStepCounter();
+12 -12
View File
@@ -28,7 +28,7 @@
#include "pokedex.h"
#include "text_window.h"
#include "menu.h"
#include "mevent.h"
#include "mystery_gift.h"
#include "naming_screen.h"
#include "party_menu.h"
#include "dynamic_placeholder_text_util.h"
@@ -1950,20 +1950,20 @@ void QuestLog_TryRecordDepartedLocation(void)
}
}
u16 BattleCardAction(void)
u16 GetMysteryGiftCardStat(void)
{
switch (gSpecialVar_Result)
{
case 0:
return MEvent_GetBattleCardCount(3);
case 1:
return MEvent_GetBattleCardCount(4);
case 2:
return MEvent_GetBattleCardCount(0);
case 3:
return MEvent_GetBattleCardCount(1);
case 4:
return MEvent_GetBattleCardCount(2);
case GET_NUM_STAMPS:
return MysteryGift_GetCardStat(CARD_STAT_NUM_STAMPS);
case GET_MAX_STAMPS:
return MysteryGift_GetCardStat(CARD_STAT_MAX_STAMPS);
case GET_CARD_BATTLES_WON:
return MysteryGift_GetCardStat(CARD_STAT_BATTLES_WON);
case GET_CARD_BATTLES_LOST:
return MysteryGift_GetCardStat(CARD_STAT_BATTLES_LOST);
case GET_CARD_NUM_TRADES:
return MysteryGift_GetCardStat(CARD_STAT_NUM_TRADES);
default:
AGB_ASSERT_EX(0, ABSPATH("scr_tool.c"), 3873);
return 0;
+1 -1
View File
@@ -481,7 +481,7 @@ static void Task_ExecuteMainMenuSelection(u8 taskId)
TrySetUpQuestLogScenes_ElseContinueFromSave(taskId);
break;
case MAIN_MENU_MYSTERYGIFT:
SetMainCallback2(c2_mystery_gift);
SetMainCallback2(CB2_InitMysteryGift);
HelpSystem_Disable();
FreeAllWindowBuffers();
DestroyTask(taskId);
-148
View File
@@ -1,148 +0,0 @@
#include "global.h"
#include "mevent.h"
#include "random.h"
#include "event_data.h"
#include "menews_jisan.h"
#include "constants/items.h"
static u32 GetMENewsJisanRewardItem(struct WonderNewsMetadata *);
static void MENewsJisanIncrementCounterUnk0_5(struct WonderNewsMetadata *);
static u32 GetMENewsJisanState(struct WonderNewsMetadata *);
static void MENewsJisanIncrementCounterUnk0_2(struct WonderNewsMetadata *);
static void MENewsJisanResetCounterUnk0_2(struct WonderNewsMetadata *);
void MENewsJisan_SetRandomReward(u32 a0)
{
struct WonderNewsMetadata *r5 = GetMENewsJisanStructPtr();
r5->unk_0_0 = a0;
switch (a0)
{
case 0:
break;
case 1:
case 2:
r5->berry = (Random() % 15) + ITEM_TO_BERRY(ITEM_RAZZ_BERRY);
break;
case 3:
r5->berry = (Random() % 15) + ITEM_TO_BERRY(ITEM_CHERI_BERRY);
break;
}
}
void MENewsJisanReset(void)
{
struct WonderNewsMetadata *r5 = GetMENewsJisanStructPtr();
r5->unk_0_0 = 0;
r5->unk_0_2 = 0;
r5->unk_0_5 = 0;
r5->berry = 0;
VarSet(VAR_MENEWS_JISAN_STEP_COUNTER, 0);
}
void MENewsJisanStepCounter(void)
{
u16 *r4 = GetVarPointer(VAR_MENEWS_JISAN_STEP_COUNTER);
struct WonderNewsMetadata *r2 = GetMENewsJisanStructPtr();
struct WonderNewsMetadata r0 = *r2;
if ((u8)r0.unk_0_5 > 4 && ++(*r4) >= 500)
{
r2->unk_0_5 = 0;
*r4 = 0;
}
}
u16 GetMENewsJisanItemAndState(void)
{
u16 *r6 = &gSpecialVar_Result;
struct WonderNewsMetadata *r4 = GetMENewsJisanStructPtr();
u16 r5;
if (!IsMysteryGiftEnabled() || !ValidateReceivedWonderNews())
return 0;
r5 = GetMENewsJisanState(r4);
switch (r5)
{
case 0:
break;
case 1:
*r6 = GetMENewsJisanRewardItem(r4);
break;
case 2:
*r6 = GetMENewsJisanRewardItem(r4);
break;
case 3:
break;
case 4:
*r6 = GetMENewsJisanRewardItem(r4);
MENewsJisanIncrementCounterUnk0_2(r4);
break;
case 5:
*r6 = GetMENewsJisanRewardItem(r4);
MENewsJisanResetCounterUnk0_2(r4);
break;
case 6:
break;
}
return r5;
}
static u32 GetMENewsJisanRewardItem(struct WonderNewsMetadata *a0)
{
u32 r4;
a0->unk_0_0 = 0;
r4 = a0->berry + FIRST_BERRY_INDEX - 1;
a0->berry = 0;
MENewsJisanIncrementCounterUnk0_5(a0);
return r4;
}
static void MENewsJisanResetCounterUnk0_2(struct WonderNewsMetadata *a0)
{
a0->unk_0_2 = 0;
}
static void MENewsJisanIncrementCounterUnk0_2(struct WonderNewsMetadata *a0)
{
a0->unk_0_2++;
if ((u8)a0->unk_0_2 > 4)
a0->unk_0_2 = 4;
}
static void MENewsJisanIncrementCounterUnk0_5(struct WonderNewsMetadata *a0)
{
a0->unk_0_5++;
if ((u8)a0->unk_0_5 > 5)
a0->unk_0_5 = 5;
}
static u32 GetMENewsJisanState(struct WonderNewsMetadata *a0)
{
struct WonderNewsMetadata r0;
if ((u8)a0->unk_0_5 == 5)
return 6;
r0 = *a0;
switch (r0.unk_0_0)
{
case 0:
return 3;
case 1:
return 1;
case 2:
return 2;
case 3:
if ((u8)r0.unk_0_2 < 3)
return 4;
return 5;
default:
AGB_ASSERT_EX(0, ABSPATH("menews_jisan.c"), 383);
return 0;
}
}
-1029
View File
File diff suppressed because it is too large Load Diff
-290
View File
@@ -1,290 +0,0 @@
#include "global.h"
#include "gflib.h"
#include "decompress.h"
#include "overworld.h"
#include "script.h"
#include "battle_tower.h"
#include "mystery_event_script.h"
#include "mevent.h"
#include "mevent_server.h"
static EWRAM_DATA struct mevent_client * s_mevent_client_ptr = NULL;
static void mevent_client_init(struct mevent_client *, u32, u32);
static u32 mevent_client_exec(struct mevent_client *);
static void mevent_client_free_resources(struct mevent_client *);
extern const struct mevent_client_cmd gMEventClientScript_InitialListen[];
void mevent_client_do_init(void)
{
s_mevent_client_ptr = AllocZeroed(sizeof(struct mevent_client));
mevent_client_init(s_mevent_client_ptr, 1, 0);
}
u32 mevent_client_do_exec(u16 * a0)
{
u32 result;
if (s_mevent_client_ptr == NULL)
return 6;
result = mevent_client_exec(s_mevent_client_ptr);
if (result == 6)
{
*a0 = s_mevent_client_ptr->param;
mevent_client_free_resources(s_mevent_client_ptr);
Free(s_mevent_client_ptr);
s_mevent_client_ptr = NULL;
}
return result;
}
void mevent_client_inc_flag(void)
{
s_mevent_client_ptr->flag++;
}
void *mevent_client_get_buffer(void)
{
return s_mevent_client_ptr->buffer;
}
void mevent_client_set_param(u32 a0)
{
s_mevent_client_ptr->param = a0;
}
static void mevent_client_init(struct mevent_client * svr, u32 sendPlayerNo, u32 recvPlayerNo)
{
svr->unk_00 = 0;
svr->mainseqno = 0;
svr->flag = 0;
svr->sendBuffer = AllocZeroed(ME_SEND_BUF_SIZE);
svr->recvBuffer = AllocZeroed(ME_SEND_BUF_SIZE);
svr->cmdBuffer = AllocZeroed(ME_SEND_BUF_SIZE);
svr->buffer = AllocZeroed(0x40);
mevent_srv_sub_init(&svr->manager, sendPlayerNo, recvPlayerNo);
}
static void mevent_client_free_resources(struct mevent_client * svr)
{
Free(svr->sendBuffer);
Free(svr->recvBuffer);
Free(svr->cmdBuffer);
Free(svr->buffer);
}
static void mevent_client_jmp_buffer(struct mevent_client * svr)
{
memcpy(svr->cmdBuffer, svr->recvBuffer, ME_SEND_BUF_SIZE);
svr->cmdidx = 0;
}
static void mevent_client_send_word(struct mevent_client * svr, u32 ident, u32 word)
{
CpuFill32(0, svr->sendBuffer, ME_SEND_BUF_SIZE);
*(u32 *)svr->sendBuffer = word;
mevent_srv_sub_init_send(&svr->manager, ident, svr->sendBuffer, sizeof(u32));
}
static u32 client_mainseq_0(struct mevent_client * svr)
{
// init
memcpy(svr->cmdBuffer, gMEventClientScript_InitialListen, ME_SEND_BUF_SIZE);
svr->cmdidx = 0;
svr->mainseqno = 4;
svr->flag = 0;
return 0;
}
static u32 client_mainseq_1(struct mevent_client * svr)
{
// done
return 6;
}
static u32 client_mainseq_2(struct mevent_client * svr)
{
// do recv
if (mevent_srv_sub_recv(&svr->manager))
{
svr->mainseqno = 4;
svr->flag = 0;
}
return 1;
}
static u32 client_mainseq_3(struct mevent_client * svr)
{
// do send
if (mevent_srv_sub_send(&svr->manager))
{
svr->mainseqno = 4;
svr->flag = 0;
}
return 1;
}
static u32 client_mainseq_4(struct mevent_client * svr)
{
// process command
struct mevent_client_cmd * cmd = &svr->cmdBuffer[svr->cmdidx];
++svr->cmdidx;
switch (cmd->instr)
{
case 0:
break;
case 1:
svr->param = cmd->parameter;
svr->mainseqno = 1;
svr->flag = 0;
break;
case 2:
mevent_srv_sub_init_recv(&svr->manager, cmd->parameter, svr->recvBuffer);
svr->mainseqno = 2;
svr->flag = 0;
break;
case 3:
svr->mainseqno = 3;
svr->flag = 0;
break;
case 20:
mevent_srv_sub_init_send(&svr->manager, 0x14, svr->sendBuffer, 0);
svr->mainseqno = 3;
svr->flag = 0;
break;
case 19:
mevent_client_send_word(svr, 0x12, GetGameStat(cmd->parameter));
svr->mainseqno = 3;
svr->flag = 0;
break;
case 6:
if (svr->param == 0)
mevent_client_jmp_buffer(svr);
break;
case 7:
if (svr->param == 1)
mevent_client_jmp_buffer(svr);
break;
case 4:
mevent_client_jmp_buffer(svr);
break;
case 5:
memcpy(svr->buffer, svr->recvBuffer, 0x40);
svr->mainseqno = 5;
svr->flag = 0;
return 2;
case 11:
memcpy(svr->buffer, svr->recvBuffer, 0x40);
svr->mainseqno = 5;
svr->flag = 0;
return 3;
case 12:
memcpy(svr->buffer, svr->recvBuffer, 0x40);
svr->mainseqno = 5;
svr->flag = 0;
return 5;
case 13:
svr->mainseqno = 5;
svr->flag = 0;
return 4;
case 8:
BuildMEventClientHeader(svr->sendBuffer);
mevent_srv_sub_init_send(&svr->manager, 0x11, svr->sendBuffer, sizeof(struct MEventClientHeaderStruct));
break;
case 14:
mevent_client_send_word(svr, 0x13, svr->param);
break;
case 10:
OverwriteSavedWonderCardWithReceivedCard(svr->recvBuffer);
break;
case 9:
if (!MEvent_HaveAlreadyReceivedWonderNews(svr->recvBuffer))
{
OverwriteSavedWonderNewsWithReceivedNews(svr->recvBuffer);
mevent_client_send_word(svr, 0x13, 0);
}
else
// Other trainer already has news
mevent_client_send_word(svr, 0x13, 1);
break;
case 15:
svr->mainseqno = 6;
svr->flag = 0;
break;
case 16:
MEvent_ReceiveDistributionMon(svr->recvBuffer);
break;
case 17:
InitRamScript_NoObjectEvent(svr->recvBuffer, 1000);
break;
case 18:
memcpy(&gSaveBlock2Ptr->battleTower.ereaderTrainer, svr->recvBuffer, sizeof(struct BattleTowerEReaderTrainer));
ValidateEReaderTrainer();
break;
case 21:
memcpy(gDecompressionBuffer, svr->recvBuffer, ME_SEND_BUF_SIZE);
svr->mainseqno = 7;
svr->flag = 0;
break;
}
return 1;
}
static u32 client_mainseq_5(struct mevent_client * svr)
{
// wait flag
if (svr->flag)
{
svr->mainseqno = 4;
svr->flag = 0;
}
return 1;
}
static u32 client_mainseq_6(struct mevent_client * svr)
{
// Run mevent buffer script
switch (svr->flag)
{
case 0:
MEventScript_InitContext(svr->recvBuffer);
++svr->flag;
break;
case 1:
if (!MEventScript_Run(&svr->param))
{
svr->mainseqno = 4;
svr->flag = 0;
}
break;
}
return 1;
}
static u32 client_mainseq_7(struct mevent_client * svr)
{
// exec arbitrary code
u32 (*func)(u32 *, struct SaveBlock2 *, struct SaveBlock1 *) = (void *)gDecompressionBuffer;
if (func(&svr->param, gSaveBlock2Ptr, gSaveBlock1Ptr) == 1)
{
svr->mainseqno = 4;
svr->flag = 0;
}
return 1;
}
static u32 mevent_client_exec(struct mevent_client * svr)
{
u32 (*funcs[])(struct mevent_client *) = {
client_mainseq_0,
client_mainseq_1,
client_mainseq_2,
client_mainseq_3,
client_mainseq_4,
client_mainseq_5,
client_mainseq_6,
client_mainseq_7
};
return funcs[svr->mainseqno](svr);
}
-192
View File
@@ -1,192 +0,0 @@
#include "global.h"
#include "mevent_server.h"
extern const struct mevent_server_cmd gServerScript_ClientCanceledCard[];
// Unreferenced
const u8 gUnknown_84687A0[] = _("You have collected all STAMPs!\nWant to input a CARD as a prize?");
/* CLIENT SCRIPTS */
const struct mevent_client_cmd gMEventClientScript_InitialListen[] = { // 84687E0
CLI_RECEIVE(0x10),
CLI_JUMPBUF
};
const struct mevent_client_cmd gMEventClientScript_Send1442CC[] = {
CLI_SNDHEAD,
CLI_WAITSND,
CLI_RECEIVE(0x10),
CLI_JUMPBUF
};
const struct mevent_client_cmd gMEventClientScript_UnableToRecv[] = { // can't accept card or news
CLI_SENDALL,
CLI_RETURN(0x0a)
};
const struct mevent_client_cmd gMEventClientScript_CommError[] = { // comm error
CLI_SENDALL,
CLI_RETURN(0x0b)
};
const struct mevent_client_cmd gMEventClientScript_NothingSentOver[] = { // nothing sent
CLI_SENDALL,
CLI_RETURN(0x00)
};
const struct mevent_client_cmd gMEventClientScript_ReceiveCardAndReturnSuccess[] = { // card success
CLI_RECEIVE(0x16),
CLI_RECVSAV,
CLI_RECEIVE(0x19),
CLI_RECVRAM,
CLI_SENDALL,
CLI_RETURN(0x02)
};
const struct mevent_client_cmd gMEventClientScript_ReceiveNewsAndValidate[] = {
CLI_RECEIVE(0x17),
CLI_VLDNEWS,
CLI_WAITSND,
CLI_RECEIVE(0x10),
CLI_JUMPBUF
};
const struct mevent_client_cmd gMEventClientScript_AlreadyHadNews[] = { // already had news
CLI_SENDALL,
CLI_RETURN(0x07)
};
const struct mevent_client_cmd gMEventClientScript_RecvNewsSuccess[] = { // news success
CLI_SENDALL,
CLI_RETURN(0x03)
};
const struct mevent_client_cmd gMEventClientScript_AskWouldLikeToTossCard[] = {
CLI_REQWORD,
CLI_SNDWORD,
CLI_WAITSND,
CLI_RECEIVE(0x10),
CLI_JUMPBUF
};
const struct mevent_client_cmd gMEventClientScript_OtherTrainerCanceled[] = { // comm canceled
CLI_SENDALL,
CLI_RETURN(0x09)
};
const struct mevent_client_cmd gMEventClientScript_AlreadyHadCard[] = { // already had card
CLI_SENDALL,
CLI_RETURN(0x05)
};
const struct mevent_client_cmd gMEventClientScript_SuccessFromBuffer[] = { // success from buffer
CLI_RECEIVE(0x15),
CLI_RECVBUF,
CLI_SENDALL,
CLI_RETURN(0x0d)
};
/* SERVER SCRIPTS */
const struct mevent_server_cmd gMEventSrvScript_UnableToSend[] = {
SRV_SEND(0x10, gMEventClientScript_UnableToRecv),
SRV_WAITSND,
SRV_RECV(0x14),
SRV_RETURN(0x0a)
};
const struct mevent_server_cmd gUnknown_8468950[] = {
SRV_SEND(0x10, gMEventClientScript_CommError),
SRV_WAITSND,
SRV_RECV(0x14),
SRV_RETURN(0x0b)
};
const struct mevent_server_cmd gUnknown_8468980[] = {
SRV_SEND(0x10, gMEventClientScript_OtherTrainerCanceled),
SRV_WAITSND,
SRV_RECV(0x14),
SRV_RETURN(0x09)
};
const struct mevent_server_cmd gMEventSrvScript_OtherTrnHasNews[] = {
SRV_SEND(0x10, gMEventClientScript_AlreadyHadNews),
SRV_WAITSND,
SRV_RECV(0x14),
SRV_RETURN(0x07)
};
const struct mevent_server_cmd gMEventSrvScript_SentNewsSuccess[] = {
SRV_SEND(0x28, gMEventClientScript_ReceiveNewsAndValidate),
SRV_WAITSND,
SRV_SEND_NEWS,
SRV_WAITSND,
SRV_RECV(0x13),
SRV_READWORD,
SRV_BRANCHIF(0x01, gMEventSrvScript_OtherTrnHasNews),
SRV_SEND(0x10, gMEventClientScript_RecvNewsSuccess),
SRV_WAITSND,
SRV_RECV(0x14),
SRV_RETURN(0x03)
};
const struct mevent_server_cmd gMEventSrvScript_SendCardSuccess[] = {
SRV_SEND(0x30, gMEventClientScript_ReceiveCardAndReturnSuccess),
SRV_WAITSND,
SRV_SEND_CARD,
SRV_WAITSND,
SRV_BUFFER_SEND,
SRV_WAITSND,
SRV_RECV(0x14),
SRV_RETURN(0x02)
};
const struct mevent_server_cmd gMEventSrvScript_AskClientToOverwriteCard[] = {
SRV_SEND(0x28, gMEventClientScript_AskWouldLikeToTossCard),
SRV_WAITSND,
SRV_RECV(0x13),
SRV_READWORD,
SRV_BRANCHIF(0x00, gMEventSrvScript_SendCardSuccess),
SRV_BRANCH(gServerScript_ClientCanceledCard)
};
const struct mevent_server_cmd gMEventSrvScript_OtherTrnHasCard[] = {
SRV_SEND(0x10, gMEventClientScript_AlreadyHadCard),
SRV_WAITSND,
SRV_RECV(0x14),
SRV_RETURN(0x05)
};
const struct mevent_server_cmd gUnknown_8468B3C[] = {
SRV_SEND(0x10, gMEventClientScript_NothingSentOver),
SRV_WAITSND,
SRV_RECV(0x14),
SRV_RETURN(0x00)
};
const struct mevent_server_cmd gMEventSrvScript_SendNews[] = {
SRV_BUFFER_NEWS,
SRV_SEND(0x20, gMEventClientScript_Send1442CC),
SRV_WAITSND,
SRV_RECV(0x11),
SRV_READ_1442CC,
SRV_VALID_1442CC,
SRV_BRANCHIF(0x00, gMEventSrvScript_UnableToSend),
SRV_BRANCH(gMEventSrvScript_SentNewsSuccess)
};
const struct mevent_server_cmd gMEventSrvScript_SendCard[] = {
SRV_BUFFER_CARD,
SRV_RAM_SCRIPT_IF_VALID,
SRV_SEND(0x20, gMEventClientScript_Send1442CC),
SRV_WAITSND,
SRV_RECV(0x11),
SRV_READ_1442CC,
SRV_VALID_1442CC,
SRV_BRANCHIF(0x00, gMEventSrvScript_UnableToSend),
SRV_CHECK_1442CC_14,
SRV_BRANCHIF(0x02, gMEventSrvScript_AskClientToOverwriteCard),
SRV_BRANCHIF(0x00, gMEventSrvScript_SendCardSuccess),
SRV_BRANCH(gMEventSrvScript_OtherTrnHasCard)
};
-279
View File
@@ -1,279 +0,0 @@
#include "global.h"
#include "gflib.h"
#include "script.h"
#include "mevent.h"
#include "mevent_server.h"
EWRAM_DATA struct mevent_srv_common * s_mevent_srv_common_ptr = NULL;
static void mevent_srv_init_common(struct mevent_srv_common *, const void *, u32, u32);
static void mevent_srv_free_resources(struct mevent_srv_common *);
static u32 mevent_srv_exec_common(struct mevent_srv_common *);
extern const struct mevent_server_cmd gMEventSrvScript_SendNews[];
extern const struct mevent_server_cmd gMEventSrvScript_SendCard[];
void mevent_srv_init_wnews(void)
{
s_mevent_srv_common_ptr = AllocZeroed(sizeof(struct mevent_srv_common));
mevent_srv_init_common(s_mevent_srv_common_ptr, gMEventSrvScript_SendNews, 0, 1);
}
void mevent_srv_new_wcard(void)
{
s_mevent_srv_common_ptr = AllocZeroed(sizeof(struct mevent_srv_common));
mevent_srv_init_common(s_mevent_srv_common_ptr, gMEventSrvScript_SendCard, 0, 1);
}
u32 mevent_srv_common_do_exec(u16 * a0)
{
u32 result;
if (s_mevent_srv_common_ptr == NULL)
return 3;
result = mevent_srv_exec_common(s_mevent_srv_common_ptr);
if (result == 3)
{
*a0 = s_mevent_srv_common_ptr->param;
mevent_srv_free_resources(s_mevent_srv_common_ptr);
Free(s_mevent_srv_common_ptr);
s_mevent_srv_common_ptr = NULL;
}
return result;
}
static void mevent_srv_init_common(struct mevent_srv_common * svr, const void *cmdBuffer, u32 sendPlayerNo, u32 recvPlayerNo)
{
svr->unk_00 = 0;
svr->mainseqno = 0;
svr->card = AllocZeroed(sizeof(struct WonderCard));
svr->news = AllocZeroed(sizeof(struct WonderNews));
svr->recvBuffer = AllocZeroed(ME_SEND_BUF_SIZE);
svr->mevent_unk1442cc = AllocZeroed(sizeof(struct MEventClientHeaderStruct));
svr->cmdBuffer = cmdBuffer;
svr->cmdidx = 0;
mevent_srv_sub_init(&svr->manager, sendPlayerNo, recvPlayerNo);
}
static void mevent_srv_free_resources(struct mevent_srv_common * svr)
{
Free(svr->card);
Free(svr->news);
Free(svr->recvBuffer);
Free(svr->mevent_unk1442cc);
}
static void mevent_srv_common_init_send(struct mevent_srv_common * svr, u32 ident, const void *src, u32 size)
{
AGB_ASSERT_EX(size <= ME_SEND_BUF_SIZE, ABSPATH("mevent_server.c"), 257);
mevent_srv_sub_init_send(&svr->manager, ident, src, size);
}
static void *mevent_first_if_not_null_else_second(void *a0, void *a1)
{
if (a0 != NULL)
return a0;
else
return a1;
}
static u32 mevent_compare_pointers(void *a0, void *a1)
{
if (a1 < a0)
return 0;
else if (a1 == a0)
return 1;
else
return 2;
}
static u32 common_mainseq_0(struct mevent_srv_common * svr)
{
// start
svr->mainseqno = 4;
return 0;
}
static u32 common_mainseq_1(struct mevent_srv_common * svr)
{
// done
return 3;
}
static u32 common_mainseq_2(struct mevent_srv_common * svr)
{
// do recv
if (mevent_srv_sub_recv(&svr->manager))
svr->mainseqno = 4;
return 1;
}
static u32 common_mainseq_3(struct mevent_srv_common * svr)
{
// do send
if (mevent_srv_sub_send(&svr->manager))
svr->mainseqno = 4;
return 1;
}
static u32 common_mainseq_4(struct mevent_srv_common * svr)
{
// process command
const struct mevent_server_cmd * cmd = &svr->cmdBuffer[svr->cmdidx];
void *ptr;
svr->cmdidx++;
switch (cmd->instr)
{
case 0:
AGB_ASSERT_EX(cmd->parameter == NULL, ABSPATH("mevent_server.c"), 354);
svr->mainseqno = 1;
svr->param = cmd->flag;
break;
case 1:
svr->mainseqno = 3;
break;
case 2:
AGB_ASSERT_EX(cmd->parameter == NULL, ABSPATH("mevent_server.c"), 364);
mevent_srv_sub_init_recv(&svr->manager, cmd->flag, svr->recvBuffer);
svr->mainseqno = 2;
break;
case 3:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 370);
svr->cmdidx = 0;
svr->cmdBuffer = cmd->parameter;
break;
case 5:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 376);
AGB_ASSERT_EX(cmd->parameter == NULL, ABSPATH("mevent_server.c"), 377);
memcpy(svr->mevent_unk1442cc, svr->recvBuffer, sizeof(struct MEventClientHeaderStruct));
break;
case 6:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 382);
AGB_ASSERT_EX(cmd->parameter == NULL, ABSPATH("mevent_server.c"), 383);
svr->param = ValidateMEventClientHeader(svr->mevent_unk1442cc);
break;
case 4:
if (svr->param == cmd->flag)
{
svr->cmdidx = 0;
svr->cmdBuffer = cmd->parameter;
}
break;
case 7:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 396);
ptr = mevent_first_if_not_null_else_second(cmd->parameter, svr->card);
svr->param = sub_8144418(ptr, svr->mevent_unk1442cc, ptr);
break;
case 8:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 402);
AGB_ASSERT_EX(cmd->parameter == NULL, ABSPATH("mevent_server.c"), 403);
svr->param = *(u32 *)svr->recvBuffer;
break;
case 9:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 408);
ptr = mevent_first_if_not_null_else_second(cmd->parameter, &svr->sendWord);
svr->param = MEvent_CanPlayerReceiveDistributionMon(ptr, svr->mevent_unk1442cc, ptr);
break;
case 10:
AGB_ASSERT_EX(cmd->parameter == NULL, ABSPATH("mevent_server.c"), 415);
svr->param = sub_81444B0(svr->mevent_unk1442cc, cmd->flag);
break;
case 11:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 420);
svr->param = sub_8144474(svr->mevent_unk1442cc, cmd->parameter);
break;
case 12:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 426);
svr->param = mevent_compare_pointers(cmd->parameter, *(void **)svr->recvBuffer);
break;
case 14:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 432);
mevent_srv_common_init_send(svr, 0x17, mevent_first_if_not_null_else_second(cmd->parameter, svr->news), sizeof(struct WonderNews));
break;
case 13:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 438);
mevent_srv_common_init_send(svr, 0x16, mevent_first_if_not_null_else_second(cmd->parameter, svr->card), sizeof(struct WonderCard));
break;
case 16:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 444);
mevent_srv_common_init_send(svr, 0x18, mevent_first_if_not_null_else_second(cmd->parameter, &svr->sendWord), 4);
break;
case 15:
if (cmd->parameter == NULL)
mevent_srv_common_init_send(svr, 0x19, svr->sendBuffer1, svr->sendBuffer1Size);
else
mevent_srv_common_init_send(svr, 0x19, cmd->parameter, cmd->flag);
break;
case 18:
if (cmd->parameter == NULL)
mevent_srv_common_init_send(svr, 0x10, svr->sendBuffer2, svr->sendBuffer2Size);
else
mevent_srv_common_init_send(svr, 0x10, cmd->parameter, cmd->flag);
break;
case 19:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 466);
mevent_srv_common_init_send(svr, 0x1a, cmd->parameter, 188);
break;
case 20:
mevent_srv_common_init_send(svr, 0x15, cmd->parameter, cmd->flag);
break;
case 17:
mevent_srv_common_init_send(svr, 0x1c, cmd->parameter, cmd->flag);
break;
case 22:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 481);
memcpy(svr->card, cmd->parameter, 332);
break;
case 23:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 486);
memcpy(svr->news, cmd->parameter, 444);
break;
case 21:
AGB_ASSERT_EX(cmd->flag == FALSE, ABSPATH("mevent_server.c"), 491);
svr->sendWord = *(u32 *)cmd->parameter;
break;
case 24:
svr->sendBuffer1 = cmd->parameter;
svr->sendBuffer1Size = cmd->flag;
break;
case 25:
svr->sendBuffer2 = cmd->parameter;
svr->sendBuffer2Size = cmd->flag;
break;
case 26:
AGB_ASSERT_EX(cmd->flag == FALSE && cmd->parameter == NULL, ABSPATH("mevent_server.c"), 506);
memcpy(svr->card, GetSavedWonderCard(), 332);
MEvent_WonderCardResetUnk08_6(svr->card);
break;
case 27:
AGB_ASSERT_EX(cmd->flag == FALSE && cmd->parameter == NULL, ABSPATH("mevent_server.c"), 512);
memcpy(svr->news, GetSavedWonderNews(), 444);
break;
case 28:
AGB_ASSERT_EX(cmd->flag == FALSE && cmd->parameter == NULL, ABSPATH("mevent_server.c"), 517);
svr->sendBuffer1 = GetSavedRamScriptIfValid();
break;
case 29:
mevent_srv_common_init_send(svr, 0x1b, cmd->parameter, cmd->flag);
break;
}
return 1;
}
static u32 (*const func_tbl[])(struct mevent_srv_common *) = {
common_mainseq_0,
common_mainseq_1,
common_mainseq_2,
common_mainseq_3,
common_mainseq_4
};
static u32 mevent_srv_exec_common(struct mevent_srv_common * svr)
{
u32 response;
AGB_ASSERT_EX(svr->mainseqno < NELEMS(func_tbl), ABSPATH("mevent_server.c"), 546);
response = func_tbl[svr->mainseqno](svr);
AGB_ASSERT_EX(svr->mainseqno < NELEMS(func_tbl), ABSPATH("mevent_server.c"), 548);
return response;
}
-204
View File
@@ -1,204 +0,0 @@
#include "global.h"
#include "util.h"
#include "link.h"
#include "link_rfu.h"
#include "mevent_server.h"
static u32 mevent_receive_func(struct mevent_srv_sub *);
static u32 mevent_send_func(struct mevent_srv_sub *);
u32 mevent_srv_sub_recv(struct mevent_srv_sub * svr)
{
return svr->recvFunc(svr);
}
u32 mevent_srv_sub_send(struct mevent_srv_sub * svr)
{
return svr->sendFunc(svr);
}
void mevent_srv_sub_init(struct mevent_srv_sub * svr, u32 sendPlayerNo, u32 recvPlayerNo)
{
svr->sendPlayerNo = sendPlayerNo;
svr->recvPlayerNo = recvPlayerNo;
svr->seqno = 0;
svr->sendCRC = 0;
svr->sendSize = 0;
svr->sendCounter = 0;
svr->recvCRC = 0;
svr->recvSize = 0;
svr->recvCounter = 0;
svr->sendBfr = NULL;
svr->recvBfr = NULL;
svr->sendFunc = mevent_send_func;
svr->recvFunc = mevent_receive_func;
}
void mevent_srv_sub_init_send(struct mevent_srv_sub * svr, u32 ident, const void *src, u32 size)
{
svr->seqno = 0;
svr->sendIdent = ident;
svr->sendCounter = 0;
svr->sendCRC = 0;
if (size != 0)
svr->sendSize = size;
else
svr->sendSize = ME_SEND_BUF_SIZE;
svr->sendBfr = src;
}
void mevent_srv_sub_init_recv(struct mevent_srv_sub * svr, u32 ident, void *dest)
{
svr->seqno = 0;
svr->recvIdent = ident;
svr->recvCounter = 0;
svr->recvCRC = 0;
svr->recvSize = 0;
svr->recvBfr = dest;
}
static void mevent_recv_block(u32 recv_idx, void *dest, size_t size)
{
memcpy(dest, gBlockRecvBuffer[recv_idx], size);
}
static bool32 mevent_has_received(u32 recv_idx)
{
if ((GetBlockReceivedStatus() >> recv_idx) & 1)
return TRUE;
else
return FALSE;
}
static void mevent_reset_recv(u32 recv_idx)
{
ResetBlockReceivedFlag(recv_idx);
}
static bool32 mevent_receive_func(struct mevent_srv_sub * svr)
{
struct send_recv_header header;
switch (svr->seqno)
{
case 0:
if (mevent_has_received(svr->recvPlayerNo))
{
mevent_recv_block(svr->recvPlayerNo, &header, sizeof(header));
svr->recvSize = header.size;
svr->recvCRC = header.crc;
if (svr->recvSize > ME_SEND_BUF_SIZE)
{
LinkRfu_FatalError();
return FALSE;
}
else if (svr->recvIdent != header.ident)
{
LinkRfu_FatalError();
return FALSE;
}
else
{
svr->recvCounter = 0;
mevent_reset_recv(svr->recvPlayerNo);
++svr->seqno;
}
}
break;
case 1:
if (mevent_has_received(svr->recvPlayerNo))
{
size_t blocksiz = svr->recvCounter * 252;
if (svr->recvSize - blocksiz <= 252)
{
mevent_recv_block(svr->recvPlayerNo, svr->recvBfr + blocksiz, svr->recvSize - blocksiz);
++svr->recvCounter;
++svr->seqno;
}
else
{
mevent_recv_block(svr->recvPlayerNo, svr->recvBfr + blocksiz, 252);
++svr->recvCounter;
}
mevent_reset_recv(svr->recvPlayerNo);
}
break;
case 2:
if (CalcCRC16WithTable(svr->recvBfr, svr->recvSize) != svr->recvCRC)
{
LinkRfu_FatalError();
return FALSE;
}
else
{
svr->seqno = 0;
return TRUE;
}
break;
}
return FALSE;
}
static bool32 mevent_send_func(struct mevent_srv_sub * svr)
{
struct send_recv_header header;
switch (svr->seqno)
{
case 0:
if (IsLinkTaskFinished())
{
header.ident = svr->sendIdent;
header.size = svr->sendSize;
header.crc = CalcCRC16WithTable(svr->sendBfr, svr->sendSize);
svr->sendCRC = header.crc;
svr->sendCounter = 0;
SendBlock(0, &header, sizeof(header));
++svr->seqno;
}
break;
case 1:
if (IsLinkTaskFinished())
{
if (mevent_has_received(svr->sendPlayerNo))
{
size_t blocksiz;
mevent_reset_recv(svr->sendPlayerNo);
blocksiz = 252 * svr->sendCounter;
if (svr->sendSize - blocksiz <= 252)
{
SendBlock(0, svr->sendBfr + blocksiz, svr->sendSize - blocksiz);
++svr->sendCounter;
++svr->seqno;
}
else
{
SendBlock(0, svr->sendBfr + blocksiz, 252);
++svr->sendCounter;
}
}
}
break;
case 2:
if (IsLinkTaskFinished())
{
if (CalcCRC16WithTable(svr->sendBfr, svr->sendSize) != svr->sendCRC)
LinkRfu_FatalError();
else
++svr->seqno;
}
break;
case 3:
if (mevent_has_received(svr->sendPlayerNo))
{
mevent_reset_recv(svr->sendPlayerNo);
svr->seqno = 0;
return TRUE;
}
break;
}
return FALSE;
}
+634
View File
@@ -0,0 +1,634 @@
#include "global.h"
#include "gflib.h"
#include "constants/songs.h"
#include "easy_chat.h"
#include "task.h"
#include "link.h"
#include "link_rfu.h"
#include "util.h"
#include "script.h"
#include "event_data.h"
#include "battle_tower.h"
#include "new_game.h"
#include "wonder_news.h"
#include "mystery_gift_menu.h"
#include "help_system.h"
#include "mystery_gift.h"
#include "strings.h"
#define CALC_CRC(data) CalcCRC16WithTable((void *)&(data), sizeof(data))
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);
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
};
static EWRAM_DATA bool32 sStatsEnabled = FALSE;
void ClearMysteryGift(void)
{
CpuFill32(0, &gSaveBlock1Ptr->mysteryGift, sizeof(gSaveBlock1Ptr->mysteryGift));
ClearSavedWonderNewsMetadata();
InitQuestionnaireWords();
}
struct WonderNews * GetSavedWonderNews(void)
{
return &gSaveBlock1Ptr->mysteryGift.news;
}
struct WonderCard * GetSavedWonderCard(void)
{
return &gSaveBlock1Ptr->mysteryGift.card;
}
struct WonderCardMetadata * GetSavedWonderCardMetadata(void)
{
return &gSaveBlock1Ptr->mysteryGift.cardMetadata;
}
struct WonderNewsMetadata * GetSavedWonderNewsMetadata(void)
{
return &gSaveBlock1Ptr->mysteryGift.newsMetadata;
}
u16 * GetQuestionnaireWordsPtr(void)
{
return gSaveBlock1Ptr->mysteryGift.questionnaireWords;
}
// Equivalent to ClearSavedWonderCardAndRelated, but nothing else to clear
void ClearSavedWonderNewsAndRelated(void)
{
ClearSavedWonderNews();
}
bool32 SaveWonderNews(const struct WonderNews * news)
{
if (!ValidateWonderNews(news))
return FALSE;
ClearSavedWonderNews();
gSaveBlock1Ptr->mysteryGift.news = *news;
gSaveBlock1Ptr->mysteryGift.newsCrc = CALC_CRC(gSaveBlock1Ptr->mysteryGift.news);
return TRUE;
}
bool32 ValidateSavedWonderNews(void)
{
if (CALC_CRC(gSaveBlock1Ptr->mysteryGift.news) != gSaveBlock1Ptr->mysteryGift.newsCrc)
return FALSE;
if (!ValidateWonderNews(&gSaveBlock1Ptr->mysteryGift.news))
return FALSE;
return TRUE;
}
static bool32 ValidateWonderNews(const struct WonderNews * news)
{
if (news->id == 0)
return FALSE;
return TRUE;
}
bool32 IsSendingSavedWonderNewsAllowed(void)
{
const struct WonderNews * news = &gSaveBlock1Ptr->mysteryGift.news;
if (news->sendType == SEND_TYPE_DISALLOWED)
return FALSE;
return TRUE;
}
static void ClearSavedWonderNews(void)
{
CpuFill32(0, GetSavedWonderNews(), sizeof(gSaveBlock1Ptr->mysteryGift.news));
gSaveBlock1Ptr->mysteryGift.newsCrc = 0;
}
static void ClearSavedWonderNewsMetadata(void)
{
CpuFill32(0, GetSavedWonderNewsMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.newsMetadata));
WonderNews_Reset();
}
bool32 IsWonderNewsSameAsSaved(const u8 * news)
{
const u8 * savedNews = (const u8 *)&gSaveBlock1Ptr->mysteryGift.news;
u32 i;
if (!ValidateSavedWonderNews())
return FALSE;
for (i = 0; i < sizeof(gSaveBlock1Ptr->mysteryGift.news); i++)
{
if (savedNews[i] != news[i])
return FALSE;
}
return TRUE;
}
void ClearSavedWonderCardAndRelated(void)
{
ClearSavedWonderCard();
ClearSavedWonderCardMetadata();
ClearSavedTrainerIds();
ClearRamScript();
ClearMysteryGiftFlags();
ClearMysteryGiftVars();
ClearEReaderTrainer(&gSaveBlock2Ptr->battleTower.ereaderTrainer);
}
bool32 SaveWonderCard(const struct WonderCard * card)
{
struct WonderCardMetadata * metadata;
if (!ValidateWonderCard(card))
return FALSE;
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 ValidateSavedWonderCard(void)
{
if (gSaveBlock1Ptr->mysteryGift.cardCrc != CALC_CRC(gSaveBlock1Ptr->mysteryGift.card))
return FALSE;
if (!ValidateWonderCard(&gSaveBlock1Ptr->mysteryGift.card))
return FALSE;
if (!ValidateRamScript())
return FALSE;
return TRUE;
}
static bool32 ValidateWonderCard(const struct WonderCard * card)
{
if (card->flagId == 0)
return FALSE;
if (card->type >= CARD_TYPE_COUNT)
return FALSE;
if (!(card->sendType == SEND_TYPE_DISALLOWED
|| card->sendType == SEND_TYPE_ALLOWED
|| card->sendType == SEND_TYPE_ALLOWED_ALWAYS))
return FALSE;
if (card->bgType >= NUM_WONDER_BGS)
return FALSE;
if (card->maxStamps > MAX_STAMP_CARD_STAMPS)
return FALSE;
return TRUE;
}
bool32 IsSendingSavedWonderCardAllowed(void)
{
const struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
if (card->sendType == SEND_TYPE_DISALLOWED)
return FALSE;
return TRUE;
}
static void ClearSavedWonderCard(void)
{
CpuFill32(0, &gSaveBlock1Ptr->mysteryGift.card, sizeof(gSaveBlock1Ptr->mysteryGift.card));
gSaveBlock1Ptr->mysteryGift.cardCrc = 0;
}
static void ClearSavedWonderCardMetadata(void)
{
CpuFill32(0, GetSavedWonderCardMetadata(), sizeof(gSaveBlock1Ptr->mysteryGift.cardMetadata));
gSaveBlock1Ptr->mysteryGift.cardMetadataCrc = 0;
}
u16 GetWonderCardFlagId(void)
{
if (ValidateSavedWonderCard())
return gSaveBlock1Ptr->mysteryGift.card.flagId;
return 0;
}
void DisableWonderCardSending(struct WonderCard * card)
{
if (card->sendType == SEND_TYPE_ALLOWED)
card->sendType = SEND_TYPE_DISALLOWED;
}
static bool32 IsWonderCardFlagIDInValidRange(u16 flagId)
{
if (flagId >= WONDER_CARD_FLAG_OFFSET && flagId < WONDER_CARD_FLAG_OFFSET + NUM_WONDER_CARD_FLAGS)
return TRUE;
return FALSE;
}
bool32 IsSavedWonderCardGiftNotReceived(void)
{
u16 value = GetWonderCardFlagId();
if (!IsWonderCardFlagIDInValidRange(value))
return FALSE;
// 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 GetNumStampsInMetadata(const struct WonderCardMetadata * data, s32 size)
{
s32 numStamps = 0;
s32 i;
for (i = 0; i < size; i++)
{
if (data->stampData[STAMP_ID][i] && data->stampData[STAMP_SPECIES][i])
numStamps++;
}
return numStamps;
}
static bool32 IsStampInMetadata(const struct WonderCardMetadata * metadata, const u16 * stamp, s32 maxStamps)
{
s32 i;
for (i = 0; i < maxStamps; i++)
{
if (metadata->stampData[STAMP_ID][i] == stamp[STAMP_ID])
return TRUE;
if (metadata->stampData[STAMP_SPECIES][i] == stamp[STAMP_SPECIES])
return TRUE;
}
return FALSE;
}
static bool32 ValidateStamp(const u16 * stamp)
{
if (stamp[STAMP_ID] == 0)
return FALSE;
if (stamp[STAMP_SPECIES] == SPECIES_NONE)
return FALSE;
if (stamp[STAMP_SPECIES] >= NUM_SPECIES)
return FALSE;
return TRUE;
}
static s32 GetNumStampsInSavedCard(void)
{
struct WonderCard * card;
if (!ValidateSavedWonderCard())
return 0;
card = &gSaveBlock1Ptr->mysteryGift.card;
if (card->type != CARD_TYPE_STAMP)
return 0;
return GetNumStampsInMetadata(&gSaveBlock1Ptr->mysteryGift.cardMetadata, card->maxStamps);
}
bool32 MysteryGift_TrySaveStamp(const u16 * stamp)
{
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
s32 maxStamps = card->maxStamps;
s32 i;
if (!ValidateStamp(stamp))
return FALSE;
if (IsStampInMetadata(&gSaveBlock1Ptr->mysteryGift.cardMetadata, stamp, maxStamps))
return FALSE;
for (i = 0; i < maxStamps; i++)
{
if (gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_ID][i] == 0
&& gSaveBlock1Ptr->mysteryGift.cardMetadata.stampData[STAMP_SPECIES][i] == SPECIES_NONE)
{
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 VERSION_CODE 1
#elif defined(LEAFGREEN)
#define VERSION_CODE 2
#endif
void MysteryGift_LoadLinkGameData(struct MysteryGiftLinkGameData * data)
{
s32 i;
CpuFill32(0, data, sizeof(*data));
// Magic
data->unk_00 = GAME_DATA_VALID_VAR;
data->unk_04 = 1;
data->unk_08 = 1;
data->unk_0C = 1;
data->unk_10 = VERSION_CODE;
// Check whether a card already exists
if (ValidateSavedWonderCard())
{
// Populate fields
data->flagId = GetSavedWonderCard()->flagId;
data->cardMetadata = *GetSavedWonderCardMetadata();
data->maxStamps = GetSavedWonderCard()->maxStamps;
}
else
{
data->flagId = 0;
}
for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++)
data->questionnaireWords[i] = gSaveBlock1Ptr->mysteryGift.questionnaireWords[i];
CopyTrainerId(data->playerTrainerId, gSaveBlock2Ptr->playerTrainerId);
StringCopy(data->playerName, gSaveBlock2Ptr->playerName);
for (i = 0; i < EASY_CHAT_BATTLE_WORDS_COUNT; i++)
data->easyChatProfile[i] = gSaveBlock1Ptr->easyChatProfile[i];
memcpy(data->gameCode, RomHeaderGameCode, GAME_CODE_LENGTH);
data->version = RomHeaderSoftwareVersion;
}
bool32 MysteryGift_ValidateLinkGameData(const struct MysteryGiftLinkGameData * data)
{
if (data->unk_00 != GAME_DATA_VALID_VAR)
return FALSE;
if (!(data->unk_04 & 1))
return FALSE;
if (!(data->unk_08 & 1))
return FALSE;
if (!(data->unk_0C & 1))
return FALSE;
if (!(data->unk_10 & 0x0F))
return FALSE;
return TRUE;
}
u32 MysteryGift_CompareCardFlags(const u16 * flagId, const struct MysteryGiftLinkGameData * data, const void *unused)
{
// Has a Wonder Card already?
if (data->flagId == 0)
return 0;
// Has this Wonder Card already?
if (*flagId == data->flagId)
return 1;
// Player has a different Wonder Card
return 2;
}
u32 MysteryGift_CheckStamps(const u16 * stamp, const struct MysteryGiftLinkGameData * data, const void *unused)
{
s32 stampsMissing = data->maxStamps - GetNumStampsInMetadata(&data->cardMetadata, data->maxStamps);
// Has full stamp card?
if (stampsMissing == 0)
return 1;
// Already has stamp?
if (IsStampInMetadata(&data->cardMetadata, stamp, data->maxStamps))
return 3;
// Only 1 empty stamp left?
if (stampsMissing == 1)
return 4;
// This is a new stamp
return 2;
}
bool32 MysteryGift_DoesQuestionnaireMatch(const struct MysteryGiftLinkGameData * data, const u16 * words)
{
s32 i;
for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++)
{
if (data->questionnaireWords[i] != words[i])
return FALSE;
}
return TRUE;
}
static s32 GetNumStampsInLinkData(const struct MysteryGiftLinkGameData * data)
{
return GetNumStampsInMetadata(&data->cardMetadata, data->maxStamps);
}
u16 MysteryGift_GetCardStatFromLinkData(const struct MysteryGiftLinkGameData * data, u32 stat)
{
switch (stat)
{
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;
}
}
static void IncrementCardStat(u32 statType)
{
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
if (card->type == CARD_TYPE_LINK_STAT)
{
u16 * stat = NULL;
switch (statType)
{
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 (stat == NULL)
{
AGB_ASSERT_EX(0, ABSPATH("mevent.c"), 868);
}
else if (++(*stat) > MAX_WONDER_CARD_STAT)
{
*stat = MAX_WONDER_CARD_STAT;
}
}
}
u16 MysteryGift_GetCardStat(u32 stat)
{
switch (stat)
{
case CARD_STAT_BATTLES_WON:
{
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
if (card->type == CARD_TYPE_LINK_STAT)
{
struct WonderCardMetadata * metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
return metadata->battlesWon;
}
break;
}
case CARD_STAT_BATTLES_LOST:
{
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
if (card->type == CARD_TYPE_LINK_STAT)
{
struct WonderCardMetadata * metadata = &gSaveBlock1Ptr->mysteryGift.cardMetadata;
return metadata->battlesLost;
}
break;
}
case CARD_STAT_NUM_TRADES:
{
struct WonderCard * card = &gSaveBlock1Ptr->mysteryGift.card;
if (card->type == CARD_TYPE_LINK_STAT)
{
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;
}
void MysteryGift_DisableStats(void)
{
sStatsEnabled = FALSE;
}
bool32 MysteryGift_TryEnableStatsByFlagId(u16 flagId)
{
sStatsEnabled = FALSE;
if (flagId == 0)
return FALSE;
if (!ValidateSavedWonderCard())
return FALSE;
if (gSaveBlock1Ptr->mysteryGift.card.flagId != flagId)
return FALSE;
sStatsEnabled = TRUE;
return TRUE;
}
void MysteryGift_TryIncrementStat(u32 stat, u32 trainerId)
{
if (sStatsEnabled)
{
switch (stat)
{
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 ClearSavedTrainerIds(void)
{
CpuFill32(0, gSaveBlock1Ptr->mysteryGift.trainerIds, sizeof(gSaveBlock1Ptr->mysteryGift.trainerIds));
}
// 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 < size; i++)
{
if (trainerIds[i] == trainerId)
break;
}
if (i == size)
{
// 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--)
trainerIds[j] = trainerIds[j - 1];
trainerIds[0] = trainerId;
return FALSE;
}
}
static void IncrementCardStatForNewTrainer(u32 stat, u32 trainerId, u32 * trainerIds, s32 size)
{
if (RecordTrainerId(trainerId, trainerIds, size))
IncrementCardStat(stat);
}
+300
View File
@@ -0,0 +1,300 @@
#include "global.h"
#include "gflib.h"
#include "decompress.h"
#include "overworld.h"
#include "script.h"
#include "battle_tower.h"
#include "mystery_event_script.h"
#include "mystery_gift.h"
#include "mystery_gift_client.h"
#include "mystery_gift_server.h"
enum {
FUNC_INIT,
FUNC_DONE,
FUNC_RECV,
FUNC_SEND,
FUNC_RUN,
FUNC_WAIT,
FUNC_RUN_MEVENT,
FUNC_RUN_BUFFER,
};
static EWRAM_DATA struct MysteryGiftClient * sClient = NULL;
static void MysteryGiftClient_Init(struct MysteryGiftClient *, u32, u32);
static u32 MysteryGiftClient_CallFunc(struct MysteryGiftClient *);
static void MysteryGiftClient_Free(struct MysteryGiftClient *);
extern const struct MysteryGiftClientCmd gMysteryGiftClientScript_Init[];
void MysteryGiftClient_Create(void)
{
sClient = AllocZeroed(sizeof(*sClient));
MysteryGiftClient_Init(sClient, 1, 0);
}
u32 MysteryGiftClient_Run(u16 * endVal)
{
u32 result;
if (sClient == NULL)
return CLI_RET_END;
result = MysteryGiftClient_CallFunc(sClient);
if (result == CLI_RET_END)
{
*endVal = sClient->param;
MysteryGiftClient_Free(sClient);
FREE_AND_SET_NULL(sClient);
}
return result;
}
void MysteryGiftClient_AdvanceState(void)
{
sClient->funcState++;
}
void *MysteryGiftClient_GetMsg(void)
{
return sClient->msg;
}
void MysteryGiftClient_SetParam(u32 val)
{
sClient->param = val;
}
static void MysteryGiftClient_Init(struct MysteryGiftClient * client, u32 sendPlayerId, u32 recvPlayerId)
{
client->unused = 0;
client->funcId = FUNC_INIT;
client->funcState = 0;
client->sendBuffer = AllocZeroed(MG_LINK_BUFFER_SIZE);
client->recvBuffer = AllocZeroed(MG_LINK_BUFFER_SIZE);
client->script = AllocZeroed(MG_LINK_BUFFER_SIZE);
client->msg = AllocZeroed(CLIENT_MAX_MSG_SIZE);
MysteryGiftLink_Init(&client->link, sendPlayerId, recvPlayerId);
}
static void MysteryGiftClient_Free(struct MysteryGiftClient * client)
{
Free(client->sendBuffer);
Free(client->recvBuffer);
Free(client->script);
Free(client->msg);
}
static void MysteryGiftClient_CopyRecvScript(struct MysteryGiftClient * client)
{
memcpy(client->script, client->recvBuffer, MG_LINK_BUFFER_SIZE);
client->cmdidx = 0;
}
static void MysteryGiftClient_InitSendWord(struct MysteryGiftClient * client, u32 ident, u32 word)
{
CpuFill32(0, client->sendBuffer, MG_LINK_BUFFER_SIZE);
*(u32 *)client->sendBuffer = word;
MysteryGiftLink_InitSend(&client->link, ident, client->sendBuffer, sizeof(word));
}
static u32 Client_Init(struct MysteryGiftClient * client)
{
memcpy(client->script, gMysteryGiftClientScript_Init, MG_LINK_BUFFER_SIZE);
client->cmdidx = 0;
client->funcId = FUNC_RUN;
client->funcState = 0;
return CLI_RET_INIT;
}
static u32 Client_Done(struct MysteryGiftClient * client)
{
return CLI_RET_END;
}
static u32 Client_Recv(struct MysteryGiftClient * client)
{
if (MysteryGiftLink_Recv(&client->link))
{
client->funcId = FUNC_RUN;
client->funcState = 0;
}
return CLI_RET_ACTIVE;
}
static u32 Client_Send(struct MysteryGiftClient * client)
{
if (MysteryGiftLink_Send(&client->link))
{
client->funcId = FUNC_RUN;
client->funcState = 0;
}
return CLI_RET_ACTIVE;
}
static u32 Client_Run(struct MysteryGiftClient * client)
{
// process command
struct MysteryGiftClientCmd * cmd = &client->script[client->cmdidx];
client->cmdidx++;
switch (cmd->instr)
{
case CLI_NONE:
break;
case CLI_RETURN:
client->param = cmd->parameter; // Set for endVal in MysteryGiftClient_Run
client->funcId = FUNC_DONE;
client->funcState = 0;
break;
case CLI_RECV:
MysteryGiftLink_InitRecv(&client->link, cmd->parameter, client->recvBuffer);
client->funcId = FUNC_RECV;
client->funcState = 0;
break;
case CLI_SEND_LOADED:
// Send without a MysteryGiftLink_InitSend
// Sends whatever has been loaded already
client->funcId = FUNC_SEND;
client->funcState = 0;
break;
case CLI_SEND_READY_END:
MysteryGiftLink_InitSend(&client->link, MG_LINKID_READY_END, client->sendBuffer, 0);
client->funcId = FUNC_SEND;
client->funcState = 0;
break;
case CLI_SEND_STAT:
MysteryGiftClient_InitSendWord(client, MG_LINKID_GAME_STAT, GetGameStat(cmd->parameter));
client->funcId = FUNC_SEND;
client->funcState = 0;
break;
case CLI_COPY_RECV_IF_N:
if (client->param == FALSE)
MysteryGiftClient_CopyRecvScript(client);
break;
case CLI_COPY_RECV_IF:
if (client->param == TRUE)
MysteryGiftClient_CopyRecvScript(client);
break;
case CLI_COPY_RECV:
MysteryGiftClient_CopyRecvScript(client);
break;
case CLI_YES_NO:
memcpy(client->msg, client->recvBuffer, CLIENT_MAX_MSG_SIZE);
client->funcId = FUNC_WAIT;
client->funcState = 0;
return CLI_RET_YES_NO;
case CLI_PRINT_MSG:
memcpy(client->msg, client->recvBuffer, CLIENT_MAX_MSG_SIZE);
client->funcId = FUNC_WAIT;
client->funcState = 0;
return CLI_RET_PRINT_MSG;
case CLI_COPY_MSG:
memcpy(client->msg, client->recvBuffer, CLIENT_MAX_MSG_SIZE);
client->funcId = FUNC_WAIT;
client->funcState = 0;
return CLI_RET_COPY_MSG;
case CLI_ASK_TOSS:
client->funcId = FUNC_WAIT;
client->funcState = 0;
return CLI_RET_ASK_TOSS;
case CLI_LOAD_GAME_DATA:
MysteryGift_LoadLinkGameData(client->sendBuffer);
MysteryGiftLink_InitSend(&client->link, MG_LINKID_GAME_DATA, client->sendBuffer, sizeof(struct MysteryGiftLinkGameData));
break;
case CLI_LOAD_TOSS_RESPONSE:
// param here is set by MG_STATE_CLIENT_ASK_TOSS or MG_STATE_CLIENT_ASK_TOSS_UNRECEIVED
MysteryGiftClient_InitSendWord(client, MG_LINKID_RESPONSE, client->param);
break;
case CLI_SAVE_CARD:
SaveWonderCard(client->recvBuffer);
break;
case CLI_SAVE_NEWS:
if (!IsWonderNewsSameAsSaved(client->recvBuffer))
{
SaveWonderNews(client->recvBuffer);
MysteryGiftClient_InitSendWord(client, MG_LINKID_RESPONSE, FALSE);
}
else
{
// Wonder News has already been saved (or is invalid).
// Prepare a signal to indicate it was not saved.
MysteryGiftClient_InitSendWord(client, MG_LINKID_RESPONSE, TRUE);
}
break;
case CLI_RUN_MEVENT_SCRIPT:
client->funcId = FUNC_RUN_MEVENT;
client->funcState = 0;
break;
case CLI_SAVE_STAMP:
MysteryGift_TrySaveStamp(client->recvBuffer);
break;
case CLI_SAVE_RAM_SCRIPT:
InitRamScript_NoObjectEvent(client->recvBuffer, sizeof(struct RamScriptData));
break;
case CLI_RECV_EREADER_TRAINER:
memcpy(&gSaveBlock2Ptr->battleTower.ereaderTrainer, client->recvBuffer, sizeof(gSaveBlock2Ptr->battleTower.ereaderTrainer));
ValidateEReaderTrainer();
break;
case CLI_RUN_BUFFER_SCRIPT:
memcpy(gDecompressionBuffer, client->recvBuffer, MG_LINK_BUFFER_SIZE);
client->funcId = FUNC_RUN_BUFFER;
client->funcState = 0;
break;
}
return CLI_RET_ACTIVE;
}
static u32 Client_Wait(struct MysteryGiftClient * client)
{
if (client->funcState)
{
client->funcId = FUNC_RUN;
client->funcState = 0;
}
return CLI_RET_ACTIVE;
}
static u32 Client_RunMysteryEventScript(struct MysteryGiftClient * client)
{
switch (client->funcState)
{
case 0:
MEventScript_InitContext(client->recvBuffer);
client->funcState++;
break;
case 1:
if (!MEventScript_Run(&client->param))
{
client->funcId = FUNC_RUN;
client->funcState = 0;
}
break;
}
return CLI_RET_ACTIVE;
}
static u32 Client_RunBufferScript(struct MysteryGiftClient * client)
{
u32 (*func)(u32 *, struct SaveBlock2 *, struct SaveBlock1 *) = (void *)gDecompressionBuffer;
if (func(&client->param, gSaveBlock2Ptr, gSaveBlock1Ptr) == 1)
{
client->funcId = FUNC_RUN;
client->funcState = 0;
}
return CLI_RET_ACTIVE;
}
static u32 MysteryGiftClient_CallFunc(struct MysteryGiftClient * client)
{
u32 (*funcs[])(struct MysteryGiftClient *) = {
[FUNC_INIT] = Client_Init,
[FUNC_DONE] = Client_Done,
[FUNC_RECV] = Client_Recv,
[FUNC_SEND] = Client_Send,
[FUNC_RUN] = Client_Run,
[FUNC_WAIT] = Client_Wait,
[FUNC_RUN_MEVENT] = Client_RunMysteryEventScript,
[FUNC_RUN_BUFFER] = Client_RunBufferScript
};
return funcs[client->funcId](client);
}
+215
View File
@@ -0,0 +1,215 @@
#include "global.h"
#include "util.h"
#include "link.h"
#include "link_rfu.h"
#include "mystery_gift_server.h"
/*
Handles the link connection functions used by the Mystery Gift client/server.
Note: MysteryGiftLink is shortened to MGL for internal functions.
*/
struct SendRecvHeader
{
u16 ident;
u16 crc;
u16 size;
};
static u32 MGL_Receive(struct MysteryGiftLink *);
static u32 MGL_Send(struct MysteryGiftLink *);
u32 MysteryGiftLink_Recv(struct MysteryGiftLink * link)
{
return link->recvFunc(link);
}
u32 MysteryGiftLink_Send(struct MysteryGiftLink * link)
{
return link->sendFunc(link);
}
void MysteryGiftLink_Init(struct MysteryGiftLink * link, u32 sendPlayerId, u32 recvPlayerId)
{
link->sendPlayerId = sendPlayerId;
link->recvPlayerId = recvPlayerId;
link->state = 0;
link->sendCRC = 0;
link->sendSize = 0;
link->sendCounter = 0;
link->recvCRC = 0;
link->recvSize = 0;
link->recvCounter = 0;
link->sendBuffer = NULL;
link->recvBuffer = NULL;
link->sendFunc = MGL_Send;
link->recvFunc = MGL_Receive;
}
void MysteryGiftLink_InitSend(struct MysteryGiftLink * link, u32 ident, const void *src, u32 size)
{
link->state = 0;
link->sendIdent = ident;
link->sendCounter = 0;
link->sendCRC = 0;
if (size != 0)
link->sendSize = size;
else
link->sendSize = MG_LINK_BUFFER_SIZE;
link->sendBuffer = src;
}
void MysteryGiftLink_InitRecv(struct MysteryGiftLink * link, u32 ident, void *dest)
{
link->state = 0;
link->recvIdent = ident;
link->recvCounter = 0;
link->recvCRC = 0;
link->recvSize = 0;
link->recvBuffer = dest;
}
static void MGL_ReceiveBlock(u32 playerId, void *dest, size_t size)
{
memcpy(dest, gBlockRecvBuffer[playerId], size);
}
static bool32 MGL_HasReceived(u32 playerId)
{
if ((GetBlockReceivedStatus() >> playerId) & 1)
return TRUE;
else
return FALSE;
}
static void MGL_ResetReceived(u32 playerId)
{
ResetBlockReceivedFlag(playerId);
}
static bool32 MGL_Receive(struct MysteryGiftLink * link)
{
struct SendRecvHeader header;
switch (link->state)
{
case 0:
if (MGL_HasReceived(link->recvPlayerId))
{
MGL_ReceiveBlock(link->recvPlayerId, &header, sizeof(header));
link->recvSize = header.size;
link->recvCRC = header.crc;
if (link->recvSize > MG_LINK_BUFFER_SIZE)
{
LinkRfu_FatalError();
return FALSE;
}
else if (link->recvIdent != header.ident)
{
LinkRfu_FatalError();
return FALSE;
}
else
{
link->recvCounter = 0;
MGL_ResetReceived(link->recvPlayerId);
link->state++;
}
}
break;
case 1:
if (MGL_HasReceived(link->recvPlayerId))
{
size_t blocksize = link->recvCounter * 252;
if (link->recvSize - blocksize <= 252)
{
MGL_ReceiveBlock(link->recvPlayerId, link->recvBuffer + blocksize, link->recvSize - blocksize);
link->recvCounter++;
link->state++;
}
else
{
MGL_ReceiveBlock(link->recvPlayerId, link->recvBuffer + blocksize, 252);
link->recvCounter++;
}
MGL_ResetReceived(link->recvPlayerId);
}
break;
case 2:
if (CalcCRC16WithTable(link->recvBuffer, link->recvSize) != link->recvCRC)
{
LinkRfu_FatalError();
return FALSE;
}
else
{
link->state = 0;
return TRUE;
}
break;
}
return FALSE;
}
static bool32 MGL_Send(struct MysteryGiftLink * link)
{
struct SendRecvHeader header;
switch (link->state)
{
case 0:
if (IsLinkTaskFinished())
{
header.ident = link->sendIdent;
header.size = link->sendSize;
header.crc = CalcCRC16WithTable(link->sendBuffer, link->sendSize);
link->sendCRC = header.crc;
link->sendCounter = 0;
SendBlock(0, &header, sizeof(header));
link->state++;
}
break;
case 1:
if (IsLinkTaskFinished())
{
if (MGL_HasReceived(link->sendPlayerId))
{
size_t blocksize;
MGL_ResetReceived(link->sendPlayerId);
blocksize = 252 * link->sendCounter;
if (link->sendSize - blocksize <= 252)
{
SendBlock(0, link->sendBuffer + blocksize, link->sendSize - blocksize);
link->sendCounter++;
link->state++;
}
else
{
SendBlock(0, link->sendBuffer + blocksize, 252);
link->sendCounter++;
}
}
}
break;
case 2:
if (IsLinkTaskFinished())
{
if (CalcCRC16WithTable(link->sendBuffer, link->sendSize) != link->sendCRC)
LinkRfu_FatalError();
else
link->state++;
}
break;
case 3:
if (MGL_HasReceived(link->sendPlayerId))
{
MGL_ResetReceived(link->sendPlayerId);
link->state = 0;
return TRUE;
}
break;
}
return FALSE;
}
+548 -600
View File
File diff suppressed because it is too large Load Diff
+198
View File
@@ -0,0 +1,198 @@
#include "global.h"
#include "mystery_gift_server.h"
#include "mystery_gift_client.h"
#include "constants/mystery_gift.h"
extern const struct MysteryGiftServerCmd gServerScript_ClientCanceledCard[];
// Unreferenced
static const u8 sText_CollectedAllStamps[] = _("You have collected all STAMPs!\nWant to input a CARD as a prize?");
//==================
// Client scripts
//==================
const struct MysteryGiftClientCmd gMysteryGiftClientScript_Init[] = {
{CLI_RECV, MG_LINKID_CLIENT_SCRIPT},
{CLI_COPY_RECV}
};
static const struct MysteryGiftClientCmd sClientScript_SendGameData[] = {
{CLI_LOAD_GAME_DATA},
{CLI_SEND_LOADED},
{CLI_RECV, MG_LINKID_CLIENT_SCRIPT},
{CLI_COPY_RECV}
};
static const struct MysteryGiftClientCmd sClientScript_CantAccept[] = {
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_CANT_ACCEPT}
};
static const struct MysteryGiftClientCmd sClientScript_CommError[] = {
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_COMM_ERROR}
};
static const struct MysteryGiftClientCmd sClientScript_NothingSent[] = {
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_NOTHING_SENT}
};
static const struct MysteryGiftClientCmd sClientScript_SaveCard[] = {
{CLI_RECV, MG_LINKID_CARD},
{CLI_SAVE_CARD},
{CLI_RECV, MG_LINKID_RAM_SCRIPT},
{CLI_SAVE_RAM_SCRIPT},
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_CARD_RECEIVED}
};
static const struct MysteryGiftClientCmd sClientScript_SaveNews[] = {
{CLI_RECV, MG_LINKID_NEWS},
{CLI_SAVE_NEWS},
{CLI_SEND_LOADED}, // Send whether or not the News was saved (read by sServerScript_SendNews)
{CLI_RECV, MG_LINKID_CLIENT_SCRIPT},
{CLI_COPY_RECV}
};
static const struct MysteryGiftClientCmd sClientScript_HadNews[] = {
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_HAD_NEWS}
};
static const struct MysteryGiftClientCmd sClientScript_NewsReceived[] = {
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_NEWS_RECEIVED}
};
static const struct MysteryGiftClientCmd sClientScript_AskToss[] = {
{CLI_ASK_TOSS},
{CLI_LOAD_TOSS_RESPONSE},
{CLI_SEND_LOADED},
{CLI_RECV, MG_LINKID_CLIENT_SCRIPT},
{CLI_COPY_RECV}
};
static const struct MysteryGiftClientCmd sClientScript_Canceled[] = {
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_COMM_CANCELED}
};
static const struct MysteryGiftClientCmd sClientScript_HadCard[] = {
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_HAD_CARD}
};
static const struct MysteryGiftClientCmd sClientScript_DynamicSuccess[] = {
{CLI_RECV, MG_LINKID_DYNAMIC_MSG},
{CLI_COPY_MSG},
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_BUFFER_SUCCESS}
};
//==================
// Server scripts
//==================
static const struct MysteryGiftServerCmd sServerScript_CantSend[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_CantAccept)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_READY_END},
{SVR_RETURN, SVR_MSG_CANT_SEND_GIFT_1}
};
static const struct MysteryGiftServerCmd sServerScript_CommError[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_CommError)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_READY_END},
{SVR_RETURN, SVR_MSG_COMM_ERROR}
};
static const struct MysteryGiftServerCmd sServerScript_ClientCanceledNews[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_Canceled)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_READY_END},
{SVR_RETURN, SVR_MSG_CLIENT_CANCELED}
};
static const struct MysteryGiftServerCmd sServerScript_HasNews[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_HadNews)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_READY_END},
{SVR_RETURN, SVR_MSG_HAS_NEWS}
};
static const struct MysteryGiftServerCmd sServerScript_SendNews[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_SaveNews)},
{SVR_SEND},
{SVR_LOAD_NEWS},
{SVR_SEND},
{SVR_RECV, MG_LINKID_RESPONSE},
{SVR_READ_RESPONSE},
{SVR_GOTO_IF_EQ, TRUE, sServerScript_HasNews}, // Wonder News was not saved
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_NewsReceived)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_READY_END},
{SVR_RETURN, SVR_MSG_NEWS_SENT}
};
static const struct MysteryGiftServerCmd sServerScript_SendCard[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_SaveCard)},
{SVR_SEND},
{SVR_LOAD_CARD},
{SVR_SEND},
{SVR_LOAD_RAM_SCRIPT},
{SVR_SEND},
{SVR_RECV, MG_LINKID_READY_END},
{SVR_RETURN, SVR_MSG_CARD_SENT}
};
static const struct MysteryGiftServerCmd sServerScript_TossPrompt[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_AskToss)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_RESPONSE},
{SVR_READ_RESPONSE},
{SVR_GOTO_IF_EQ, FALSE, sServerScript_SendCard}, // Tossed old card, send new one
{SVR_GOTO, .ptr = gServerScript_ClientCanceledCard} // Kept old card, cancel new one
};
static const struct MysteryGiftServerCmd sServerScript_HasCard[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_HadCard)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_READY_END},
{SVR_RETURN, SVR_MSG_HAS_CARD}
};
static const struct MysteryGiftServerCmd sServerScript_NothingSent[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_NothingSent)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_READY_END},
{SVR_RETURN, SVR_MSG_NOTHING_SENT}
};
const struct MysteryGiftServerCmd gMysteryGiftServerScript_SendWonderNews[] = {
{SVR_COPY_SAVED_NEWS},
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_SendGameData)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_GAME_DATA},
{SVR_COPY_GAME_DATA},
{SVR_CHECK_GAME_DATA},
{SVR_GOTO_IF_EQ, FALSE, sServerScript_CantSend},
{SVR_GOTO, .ptr = sServerScript_SendNews},
};
const struct MysteryGiftServerCmd gMysteryGiftServerScript_SendWonderCard[] = {
{SVR_COPY_SAVED_CARD},
{SVR_COPY_SAVED_RAM_SCRIPT},
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_SendGameData)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_GAME_DATA},
{SVR_COPY_GAME_DATA},
{SVR_CHECK_GAME_DATA},
{SVR_GOTO_IF_EQ, FALSE, sServerScript_CantSend},
{SVR_CHECK_EXISTING_CARD},
{SVR_GOTO_IF_EQ, HAS_DIFF_CARD, sServerScript_TossPrompt},
{SVR_GOTO_IF_EQ, HAS_NO_CARD, sServerScript_SendCard},
{SVR_GOTO, .ptr = sServerScript_HasCard} // HAS_SAME_CARD
};
+302
View File
@@ -0,0 +1,302 @@
#include "global.h"
#include "gflib.h"
#include "script.h"
#include "mystery_gift.h"
#include "mystery_gift_server.h"
// Assert statements use the original GF names, which are defined below.
// Note that their name "flag" is especially misleading,
// as it's not a boolean (for example it can contain a size argument).
// 'parameter' is shortened to param explicitly to avoid a collision with
// the original name for a different field.
#define mainseqno funcId
#define func_tbl sFuncTable
#define parameter ptr
#define flag param
#define ME_SEND_BUF_SIZE MG_LINK_BUFFER_SIZE
#define FILE ABSPATH("mevent_server.c")
#define ASSERT_PTR_EMPTY(lineNum) AGB_ASSERT_EX(cmd->parameter == NULL, FILE, (lineNum));
#define ASSERT_PARAM_EMPTY(lineNum) AGB_ASSERT_EX(cmd->flag == FALSE, FILE, (lineNum));
#define ASSERT_PTR_PARAM_EMPTY(lineNum) AGB_ASSERT_EX(cmd->flag == FALSE && cmd->parameter == NULL, FILE, (lineNum));
#define ASSERT_VALID_FUNC(lineNum) AGB_ASSERT_EX(svr->mainseqno < NELEMS(func_tbl), FILE, (lineNum));
#define ASSERT_SIZE_OK(lineNum) AGB_ASSERT_EX(size <= ME_SEND_BUF_SIZE, FILE, (lineNum));
enum {
FUNC_INIT,
FUNC_DONE,
FUNC_RECV,
FUNC_SEND,
FUNC_RUN,
};
static EWRAM_DATA struct MysteryGiftServer * sServer = NULL;
static void MysteryGiftServer_Init(struct MysteryGiftServer *, const void *, u32, u32);
static void MysteryGiftServer_Free(struct MysteryGiftServer *);
static u32 MysteryGiftServer_CallFunc(struct MysteryGiftServer *);
extern const struct MysteryGiftServerCmd gMysteryGiftServerScript_SendWonderNews[];
extern const struct MysteryGiftServerCmd gMysteryGiftServerScript_SendWonderCard[];
void MysterGiftServer_CreateForNews(void)
{
sServer = AllocZeroed(sizeof(*sServer));
MysteryGiftServer_Init(sServer, gMysteryGiftServerScript_SendWonderNews, 0, 1);
}
void MysterGiftServer_CreateForCard(void)
{
sServer = AllocZeroed(sizeof(*sServer));
MysteryGiftServer_Init(sServer, gMysteryGiftServerScript_SendWonderCard, 0, 1);
}
u32 MysterGiftServer_Run(u16 * endVal)
{
u32 result;
if (sServer == NULL)
return SVR_RET_END;
result = MysteryGiftServer_CallFunc(sServer);
if (result == SVR_RET_END)
{
*endVal = sServer->param;
MysteryGiftServer_Free(sServer);
FREE_AND_SET_NULL(sServer);
}
return result;
}
static void MysteryGiftServer_Init(struct MysteryGiftServer * svr, const void *script, u32 sendPlayerId, u32 recvPlayerId)
{
svr->unused = 0;
svr->funcId = FUNC_INIT;
svr->card = AllocZeroed(sizeof(*svr->card));
svr->news = AllocZeroed(sizeof(*svr->news));
svr->recvBuffer = AllocZeroed(MG_LINK_BUFFER_SIZE);
svr->linkGameData = AllocZeroed(sizeof(*svr->linkGameData));
svr->script = script;
svr->cmdidx = 0;
MysteryGiftLink_Init(&svr->manager, sendPlayerId, recvPlayerId);
}
static void MysteryGiftServer_Free(struct MysteryGiftServer * svr)
{
Free(svr->card);
Free(svr->news);
Free(svr->recvBuffer);
Free(svr->linkGameData);
}
static void MysteryGiftServer_InitSend(struct MysteryGiftServer * svr, u32 ident, const void *src, u32 size)
{
ASSERT_SIZE_OK(257);
MysteryGiftLink_InitSend(&svr->manager, ident, src, size);
}
// Given the command pointer parameter and the 'default' normal data.
// If the command's pointer is not empty use that as the send data, otherwise use the default.
static const void *MysteryGiftServer_GetSendData(const void *dynamicData, const void *defaultData)
{
if (dynamicData != NULL)
return dynamicData;
else
return defaultData;
}
static u32 MysteryGiftServer_Compare(const void *a, const void *b)
{
if (b < a)
return 0;
else if (b == a)
return 1;
else
return 2;
}
static u32 Server_Init(struct MysteryGiftServer * svr)
{
svr->funcId = FUNC_RUN;
return SVR_RET_INIT;
}
static u32 Server_Done(struct MysteryGiftServer * svr)
{
return SVR_RET_END;
}
static u32 Server_Recv(struct MysteryGiftServer * svr)
{
if (MysteryGiftLink_Recv(&svr->manager))
svr->funcId = FUNC_RUN;
return SVR_RET_ACTIVE;
}
static u32 Server_Send(struct MysteryGiftServer * svr)
{
if (MysteryGiftLink_Send(&svr->manager))
svr->funcId = FUNC_RUN;
return SVR_RET_ACTIVE;
}
static u32 Server_Run(struct MysteryGiftServer * svr)
{
// process command
const struct MysteryGiftServerCmd * cmd = &svr->script[svr->cmdidx];
const void *ptr;
svr->cmdidx++;
switch (cmd->instr)
{
case SVR_RETURN:
ASSERT_PTR_EMPTY(354);
svr->funcId = FUNC_DONE;
svr->param = cmd->param; // Set for endVal in MysteryGiftServer_Run
break;
case SVR_SEND:
svr->funcId = FUNC_SEND;
break;
case SVR_RECV:
ASSERT_PTR_EMPTY(364);
MysteryGiftLink_InitRecv(&svr->manager, cmd->param, svr->recvBuffer);
svr->funcId = FUNC_RECV;
break;
case SVR_GOTO:
ASSERT_PARAM_EMPTY(370);
svr->cmdidx = 0;
svr->script = cmd->ptr;
break;
case SVR_COPY_GAME_DATA:
ASSERT_PARAM_EMPTY(376);
ASSERT_PTR_EMPTY(377);
memcpy(svr->linkGameData, svr->recvBuffer, sizeof(*svr->linkGameData));
break;
case SVR_CHECK_GAME_DATA:
ASSERT_PARAM_EMPTY(382);
ASSERT_PTR_EMPTY(383);
svr->param = MysteryGift_ValidateLinkGameData(svr->linkGameData);
break;
case SVR_GOTO_IF_EQ:
if (svr->param == cmd->param)
{
svr->cmdidx = 0;
svr->script = cmd->ptr;
}
break;
case SVR_CHECK_EXISTING_CARD:
ASSERT_PARAM_EMPTY(396);
ptr = MysteryGiftServer_GetSendData(cmd->ptr, svr->card);
svr->param = MysteryGift_CompareCardFlags(ptr, svr->linkGameData, ptr);
break;
case SVR_READ_RESPONSE:
ASSERT_PARAM_EMPTY(402);
ASSERT_PTR_EMPTY(403);
svr->param = *(u32 *)svr->recvBuffer;
break;
case SVR_CHECK_EXISTING_STAMPS:
ASSERT_PARAM_EMPTY(408);
ptr = MysteryGiftServer_GetSendData(cmd->ptr, &svr->stamp);
svr->param = MysteryGift_CheckStamps(ptr, svr->linkGameData, ptr);
break;
case SVR_GET_CARD_STAT:
ASSERT_PTR_EMPTY(415);
svr->param = MysteryGift_GetCardStatFromLinkData(svr->linkGameData, cmd->param);
break;
case SVR_CHECK_QUESTIONNAIRE:
ASSERT_PARAM_EMPTY(420);
svr->param = MysteryGift_DoesQuestionnaireMatch(svr->linkGameData, cmd->ptr);
break;
case SVR_COMPARE:
ASSERT_PARAM_EMPTY(426);
svr->param = MysteryGiftServer_Compare(cmd->ptr, *(void **)svr->recvBuffer);
break;
case SVR_LOAD_NEWS:
ASSERT_PARAM_EMPTY(432);
MysteryGiftServer_InitSend(svr, MG_LINKID_NEWS, MysteryGiftServer_GetSendData(cmd->ptr, svr->news), sizeof(struct WonderNews));
break;
case SVR_LOAD_CARD:
ASSERT_PARAM_EMPTY(438);
MysteryGiftServer_InitSend(svr, MG_LINKID_CARD, MysteryGiftServer_GetSendData(cmd->ptr, svr->card), sizeof(struct WonderCard));
break;
case SVR_LOAD_STAMP:
ASSERT_PARAM_EMPTY(444);
MysteryGiftServer_InitSend(svr, MG_LINKID_STAMP, MysteryGiftServer_GetSendData(cmd->ptr, &svr->stamp), sizeof(svr->stamp));
break;
case SVR_LOAD_RAM_SCRIPT:
if (cmd->ptr == NULL)
MysteryGiftServer_InitSend(svr, MG_LINKID_RAM_SCRIPT, svr->ramScript, svr->ramScriptSize);
else
MysteryGiftServer_InitSend(svr, MG_LINKID_RAM_SCRIPT, cmd->ptr, cmd->param);
break;
case SVR_LOAD_CLIENT_SCRIPT:
if (cmd->ptr == NULL)
MysteryGiftServer_InitSend(svr, MG_LINKID_CLIENT_SCRIPT, svr->clientScript, svr->clientScriptSize);
else
MysteryGiftServer_InitSend(svr, MG_LINKID_CLIENT_SCRIPT, cmd->ptr, cmd->param);
break;
case SVR_LOAD_EREADER_TRAINER:
ASSERT_PARAM_EMPTY(466);
MysteryGiftServer_InitSend(svr, MG_LINKID_EREADER_TRAINER, cmd->ptr, sizeof(struct BattleTowerEReaderTrainer));
break;
case SVR_LOAD_MSG:
MysteryGiftServer_InitSend(svr, MG_LINKID_DYNAMIC_MSG, cmd->ptr, cmd->param);
break;
case SVR_LOAD_UNK_2:
MysteryGiftServer_InitSend(svr, MG_LINKID_UNK_2, cmd->ptr, cmd->param);
break;
case SVR_COPY_CARD:
ASSERT_PARAM_EMPTY(481);
memcpy(svr->card, cmd->ptr, sizeof(*svr->card));
break;
case SVR_COPY_NEWS:
ASSERT_PARAM_EMPTY(486);
memcpy(svr->news, cmd->ptr, sizeof(*svr->news));
break;
case SVR_COPY_STAMP:
ASSERT_PARAM_EMPTY(491);
svr->stamp = *(u32 *)cmd->ptr;
break;
case SVR_SET_RAM_SCRIPT:
svr->ramScript = cmd->ptr;
svr->ramScriptSize = cmd->param;
break;
case SVR_SET_CLIENT_SCRIPT:
svr->clientScript = cmd->ptr;
svr->clientScriptSize = cmd->param;
break;
case SVR_COPY_SAVED_CARD:
ASSERT_PTR_PARAM_EMPTY(506);
memcpy(svr->card, GetSavedWonderCard(), sizeof(*svr->card));
DisableWonderCardSending(svr->card);
break;
case SVR_COPY_SAVED_NEWS:
ASSERT_PTR_PARAM_EMPTY(512);
memcpy(svr->news, GetSavedWonderNews(), sizeof(*svr->news));
break;
case SVR_COPY_SAVED_RAM_SCRIPT:
ASSERT_PTR_PARAM_EMPTY(517);
svr->ramScript = GetSavedRamScriptIfValid();
break;
case SVR_LOAD_UNK_1:
MysteryGiftServer_InitSend(svr, MG_LINKID_UNK_1, cmd->ptr, cmd->param);
break;
}
return SVR_RET_ACTIVE;
}
static u32 (*const sFuncTable[])(struct MysteryGiftServer *) = {
[FUNC_INIT] = Server_Init,
[FUNC_DONE] = Server_Done,
[FUNC_RECV] = Server_Recv,
[FUNC_SEND] = Server_Send,
[FUNC_RUN] = Server_Run
};
static u32 MysteryGiftServer_CallFunc(struct MysteryGiftServer * svr)
{
u32 response;
ASSERT_VALID_FUNC(546)
response = sFuncTable[svr->funcId](svr);
ASSERT_VALID_FUNC(548)
return response;
}
+1 -1
View File
@@ -5,7 +5,7 @@
#include "new_menu_helpers.h"
#include "pokemon_icon.h"
#include "mystery_gift_menu.h"
#include "mevent.h"
#include "mystery_gift.h"
#include "battle_anim.h"
#include "constants/mystery_gift.h"
+1 -1
View File
@@ -2,7 +2,7 @@
#include "gflib.h"
#include "menu_indicators.h"
#include "new_menu_helpers.h"
#include "mevent.h"
#include "mystery_gift.h"
#include "mystery_gift_menu.h"
#include "menu.h"
#include "link_rfu.h"
+2 -2
View File
@@ -22,7 +22,7 @@
#include "berry.h"
#include "easy_chat.h"
#include "union_room_chat.h"
#include "mevent.h"
#include "mystery_gift.h"
#include "renewable_hidden_items.h"
#include "trainer_tower.h"
#include "script.h"
@@ -143,7 +143,7 @@ void NewGameInitData(void)
ResetTrainerFanClub();
UnionRoomChat_InitializeRegisteredTexts();
ResetMiniGamesResults();
InitMEventData();
ClearMysteryGift();
SetAllRenewableItemFlags();
WarpToPlayersRoom();
RunScriptImmediately(EventScript_ResetAllMapFlags);
+170 -131
View File
@@ -4,160 +4,191 @@
#include "task.h"
#include "wild_pokemon_area.h"
#include "pokedex_area_markers.h"
#include "pokedex.h"
/*
Controls the red ellipse markers that appear on the pokedex maps to show where a species is found.
All of the markers together are a single sprite, with each individual marker being represented by
a subsprite of the necessary size and shape.
The data about each area marker is in sAreaMarkers, each specified by a DEX_AREA constant.
A MAPSEC is associated with a DEX_AREA constant by a series of arrays in wild_pokemon_area.c
*/
struct PAM_TaskData
{
struct SubspriteTable subsprites;
void *buffer;
u8 unused;
u8 spriteId;
u16 tilesTag;
u16 paletteTag; // Never read
};
enum {
MARKER_CIRCULAR,
MARKER_SMALL_H,
MARKER_SMALL_V,
MARKER_MED_H,
MARKER_MED_V,
MARKER_LARGE_H,
MARKER_LARGE_V,
};
static const u16 sMarkerPal[] = INCBIN_U16("graphics/pokedex/area_markers/marker.gbapal");
static const u32 sMarkerTiles[] = INCBIN_U32("graphics/pokedex/area_markers/marker.4bpp.lz");
static const struct Subsprite sSubsprite0 = {
.size = ST_OAM_SIZE_0,
.shape = ST_OAM_SQUARE,
static const struct Subsprite sSubsprite_Circular = {
.size = SPRITE_SIZE(8x8),
.shape = SPRITE_SHAPE(8x8),
.priority = 1,
.tileOffset = 0
};
static const struct Subsprite sSubsprite1 = {
.size = ST_OAM_SIZE_0,
.shape = ST_OAM_H_RECTANGLE,
static const struct Subsprite sSubsprite_SmallHorizontal = {
.size = SPRITE_SIZE(16x8),
.shape = SPRITE_SHAPE(16x8),
.priority = 1,
.tileOffset = 1
};
static const struct Subsprite sSubsprite2 = {
.size = ST_OAM_SIZE_0,
.shape = ST_OAM_V_RECTANGLE,
static const struct Subsprite sSubsprite_SmallVertical = {
.size = SPRITE_SIZE(8x16),
.shape = SPRITE_SHAPE(8x16),
.priority = 1,
.tileOffset = 3
};
static const struct Subsprite sSubsprite3 = {
.size = ST_OAM_SIZE_2,
.shape = ST_OAM_H_RECTANGLE,
static const struct Subsprite sSubsprite_MediumHorizontal = {
.size = SPRITE_SIZE(32x16),
.shape = SPRITE_SHAPE(32x16),
.priority = 1,
.tileOffset = 5
};
static const struct Subsprite sSubsprite4 = {
.size = ST_OAM_SIZE_2,
.shape = ST_OAM_V_RECTANGLE,
static const struct Subsprite sSubsprite_MediumVertical = {
.size = SPRITE_SIZE(16x32),
.shape = SPRITE_SHAPE(16x32),
.priority = 1,
.tileOffset = 13
};
static const struct Subsprite sSubsprite5 = {
.size = ST_OAM_SIZE_2,
.shape = ST_OAM_H_RECTANGLE,
static const struct Subsprite sSubsprite_LargeHorizontal = {
.size = SPRITE_SIZE(32x16),
.shape = SPRITE_SHAPE(32x16),
.priority = 1,
.tileOffset = 21
};
static const struct Subsprite sSubsprite6 = {
.size = ST_OAM_SIZE_2,
.shape = ST_OAM_V_RECTANGLE,
static const struct Subsprite sSubsprite_LargeVertical = {
.size = SPRITE_SIZE(16x32),
.shape = SPRITE_SHAPE(16x32),
.priority = 1,
.tileOffset = 29
};
static const struct Subsprite *const sSubsprites[] = {
&sSubsprite0,
&sSubsprite1,
&sSubsprite2,
&sSubsprite3,
&sSubsprite4,
&sSubsprite5,
&sSubsprite6
[MARKER_CIRCULAR] = &sSubsprite_Circular,
[MARKER_SMALL_H] = &sSubsprite_SmallHorizontal,
[MARKER_SMALL_V] = &sSubsprite_SmallVertical,
[MARKER_MED_H] = &sSubsprite_MediumHorizontal,
[MARKER_MED_V] = &sSubsprite_MediumVertical,
[MARKER_LARGE_H] = &sSubsprite_LargeHorizontal,
[MARKER_LARGE_V] = &sSubsprite_LargeVertical
};
static const s8 sSubspriteLookupTable[][4] = {
{ 0, 0x00, 0x00 },
{ 0, 0x36, 0x2c },
{ 0, 0x36, 0x1c },
{ 0, 0x36, 0x0c },
{ 0, 0x5c, 0x0c },
{ 0, 0x6e, 0x18 },
{ 0, 0x5c, 0x24 },
{ 0, 0x4c, 0x18 },
{ 0, 0x4e, 0x34 },
{ 0, 0x36, 0x3e },
{ 0, 0x2a, 0x02 },
{ 0, 0x5c, 0x18 },
{ 2, 0x36, 0x20 },
{ 2, 0x36, 0x10 },
{ 1, 0x3d, 0x0c },
{ 1, 0x4d, 0x0c },
{ 0, 0x5c, 0x12 },
{ 0, 0x5c, 0x1e },
{ 0, 0x54, 0x18 },
{ 1, 0x62, 0x18 },
{ 1, 0x62, 0x0c },
{ 2, 0x6e, 0x0c },
{ 1, 0x62, 0x24 },
{ 4, 0x6a, 0x19 },
{ 1, 0x64, 0x2e },
{ 2, 0x5e, 0x2d },
{ 1, 0x55, 0x34 },
{ 0, 0x44, 0x18 },
{ 4, 0x3e, 0x1a },
{ 1, 0x40, 0x34 },
{ 0, 0x4e, 0x3c },
{ 3, 0x37, 0x3a },
{ 2, 0x36, 0x32 },
{ 1, 0x28, 0x1c },
{ 4, 0x26, 0x04 },
{ 0, 0x5c, 0x04 },
{ 3, 0x5a, 0xfe },
{ 0, 0x33, 0x14 },
{ 1, 0x3d, 0x12 },
{ 0, 0x48, 0x08 },
{ 0, 0x57, 0x08 },
{ 0, 0x70, 0x0e },
{ 0, 0x71, 0x14 },
{ 0, 0x71, 0x19 },
{ 1, 0x4e, 0x2c },
{ 0, 0x41, 0x3c },
{ 0, 0x34, 0x3e },
{ 0, 0x2d, 0x07 },
{ 0, 0x0a, 0x0a },
{ 0, 0x0c, 0x23 },
{ 0, 0x0e, 0x34 },
{ 0, 0x0c, 0x54 },
{ 0, 0x2d, 0x51 },
{ 0, 0x4c, 0x54 },
{ 0, 0x68, 0x52 },
{ 2, 0x0e, 0x02 },
{ 0, 0x0a, 0x0f },
{ 0, 0x0c, 0x1d },
{ 1, 0x02, 0x34 },
{ 1, 0x0c, 0x38 },
{ 1, 0x2c, 0x4a },
{ 1, 0x24, 0x4e },
{ 2, 0x30, 0x50 },
{ 2, 0x34, 0x56 },
{ 0, 0x48, 0x4a },
{ 1, 0x48, 0x4e },
{ 2, 0x51, 0x50 },
{ 0, 0x4c, 0x5c },
{ 0, 0x68, 0x4b },
{ 0, 0x68, 0x56 },
{ 2, 0x6c, 0x53 },
{ 3, 0x60, 0x5a },
{ 0, 0x0e, 0x01 },
{ 0, 0x05, 0x34 },
{ 0, 0x0d, 0x50 },
{ 0, 0x36, 0x4a },
{ 0, 0x45, 0x49 },
{ 0, 0x4c, 0x4d },
{ 0, 0x49, 0x5f },
{ 3, 0x60, 0x5a }
static const s8 sAreaMarkers[][4] = {
// Marker, x, y
[DEX_AREA_NONE] = {},
[DEX_AREA_PALLET_TOWN] = { MARKER_CIRCULAR, 54, 44 },
[DEX_AREA_VIRIDIAN_CITY] = { MARKER_CIRCULAR, 54, 28 },
[DEX_AREA_PEWTER_CITY] = { MARKER_CIRCULAR, 54, 12 },
[DEX_AREA_CERULEAN_CITY] = { MARKER_CIRCULAR, 92, 12 },
[DEX_AREA_LAVENDER_TOWN] = { MARKER_CIRCULAR, 110, 24 },
[DEX_AREA_VERMILION_CITY] = { MARKER_CIRCULAR, 92, 36 },
[DEX_AREA_CELADON_CITY] = { MARKER_CIRCULAR, 76, 24 },
[DEX_AREA_FUCHSIA_CITY] = { MARKER_CIRCULAR, 78, 52 },
[DEX_AREA_CINNABAR_ISLAND] = { MARKER_CIRCULAR, 54, 62 },
[DEX_AREA_INDIGO_PLATEAU] = { MARKER_CIRCULAR, 42, 2 },
[DEX_AREA_SAFFRON_CITY] = { MARKER_CIRCULAR, 92, 24 },
[DEX_AREA_ROUTE_1] = { MARKER_SMALL_V, 54, 32 },
[DEX_AREA_ROUTE_2] = { MARKER_SMALL_V, 54, 16 },
[DEX_AREA_ROUTE_3] = { MARKER_SMALL_H, 61, 12 },
[DEX_AREA_ROUTE_4] = { MARKER_SMALL_H, 77, 12 },
[DEX_AREA_ROUTE_5] = { MARKER_CIRCULAR, 92, 18 },
[DEX_AREA_ROUTE_6] = { MARKER_CIRCULAR, 92, 30 },
[DEX_AREA_ROUTE_7] = { MARKER_CIRCULAR, 84, 24 },
[DEX_AREA_ROUTE_8] = { MARKER_SMALL_H, 98, 24 },
[DEX_AREA_ROUTE_9] = { MARKER_SMALL_H, 98, 12 },
[DEX_AREA_ROUTE_10] = { MARKER_SMALL_V, 110, 12 },
[DEX_AREA_ROUTE_11] = { MARKER_SMALL_H, 98, 36 },
[DEX_AREA_ROUTE_12] = { MARKER_MED_V, 106, 25 },
[DEX_AREA_ROUTE_13] = { MARKER_SMALL_H, 100, 46 },
[DEX_AREA_ROUTE_14] = { MARKER_SMALL_V, 94, 45 },
[DEX_AREA_ROUTE_15] = { MARKER_SMALL_H, 85, 52 },
[DEX_AREA_ROUTE_16] = { MARKER_CIRCULAR, 68, 24 },
[DEX_AREA_ROUTE_17] = { MARKER_MED_V, 62, 26 },
[DEX_AREA_ROUTE_18] = { MARKER_SMALL_H, 64, 52 },
[DEX_AREA_ROUTE_19] = { MARKER_CIRCULAR, 78, 60 },
[DEX_AREA_ROUTE_20] = { MARKER_MED_H, 55, 58 },
[DEX_AREA_ROUTE_21] = { MARKER_SMALL_V, 54, 50 },
[DEX_AREA_ROUTE_22] = { MARKER_SMALL_H, 40, 28 },
[DEX_AREA_ROUTE_23] = { MARKER_MED_V, 38, 4 },
[DEX_AREA_ROUTE_24] = { MARKER_CIRCULAR, 92, 4 },
[DEX_AREA_ROUTE_25] = { MARKER_MED_H, 90, -2 },
[DEX_AREA_VIRIDIAN_FOREST] = { MARKER_CIRCULAR, 51, 20 },
[DEX_AREA_DIGLETTS_CAVE] = { MARKER_SMALL_H, 61, 18 },
[DEX_AREA_MT_MOON] = { MARKER_CIRCULAR, 72, 8 },
[DEX_AREA_CERULEAN_CAVE] = { MARKER_CIRCULAR, 87, 8 },
[DEX_AREA_ROCK_TUNNEL] = { MARKER_CIRCULAR, 112, 14 },
[DEX_AREA_POWER_PLANT] = { MARKER_CIRCULAR, 113, 20 },
[DEX_AREA_POKEMON_TOWER] = { MARKER_CIRCULAR, 113, 25 },
[DEX_AREA_SAFARI_ZONE] = { MARKER_SMALL_H, 78, 44 },
[DEX_AREA_SEAFOAM_ISLANDS] = { MARKER_CIRCULAR, 65, 60 },
[DEX_AREA_POKEMON_MANSION] = { MARKER_CIRCULAR, 52, 62 },
[DEX_AREA_VICTORY_ROAD] = { MARKER_CIRCULAR, 45, 7 },
[DEX_AREA_ONE_ISLAND] = { MARKER_CIRCULAR, 10, 10 },
[DEX_AREA_TWO_ISLAND] = { MARKER_CIRCULAR, 12, 35 },
[DEX_AREA_THREE_ISLAND] = { MARKER_CIRCULAR, 14, 52 },
[DEX_AREA_FOUR_ISLAND] = { MARKER_CIRCULAR, 12, 84 },
[DEX_AREA_FIVE_ISLAND] = { MARKER_CIRCULAR, 45, 81 },
[DEX_AREA_SIX_ISLAND] = { MARKER_CIRCULAR, 76, 84 },
[DEX_AREA_SEVEN_ISLAND] = { MARKER_CIRCULAR, 104, 82 },
[DEX_AREA_KINDLE_ROAD] = { MARKER_SMALL_V, 14, 2 },
[DEX_AREA_TREASURE_BEACH] = { MARKER_CIRCULAR, 10, 15 },
[DEX_AREA_CAPE_BRINK] = { MARKER_CIRCULAR, 12, 29 },
[DEX_AREA_BOND_BRIDGE] = { MARKER_SMALL_H, 2, 52 },
[DEX_AREA_THREE_ISLE_PATH] = { MARKER_SMALL_H, 12, 56 },
[DEX_AREA_RESORT_GORGEOUS] = { MARKER_SMALL_H, 44, 74 },
[DEX_AREA_WATER_LABYRINTH] = { MARKER_SMALL_H, 36, 78 },
[DEX_AREA_FIVE_ISLE_MEADOW] = { MARKER_SMALL_V, 48, 80 },
[DEX_AREA_MEMORIAL_PILLAR] = { MARKER_SMALL_V, 52, 86 },
[DEX_AREA_OUTCAST_ISLAND] = { MARKER_CIRCULAR, 72, 74 },
[DEX_AREA_GREEN_PATH] = { MARKER_SMALL_H, 72, 78 },
[DEX_AREA_WATER_PATH] = { MARKER_SMALL_V, 81, 80 },
[DEX_AREA_RUIN_VALLEY] = { MARKER_CIRCULAR, 76, 92 },
[DEX_AREA_TRAINER_TOWER] = { MARKER_CIRCULAR, 104, 75 },
[DEX_AREA_CANYON_ENTRANCE] = { MARKER_CIRCULAR, 104, 86 },
[DEX_AREA_SEVAULT_CANYON] = { MARKER_SMALL_V, 108, 83 },
[DEX_AREA_TANOBY_RUINS] = { MARKER_MED_H, 96, 90 },
[DEX_AREA_MT_EMBER] = { MARKER_CIRCULAR, 14, 1 },
[DEX_AREA_BERRY_FOREST] = { MARKER_CIRCULAR, 5, 52 },
[DEX_AREA_ICEFALL_CAVE] = { MARKER_CIRCULAR, 13, 80 },
[DEX_AREA_LOST_CAVE] = { MARKER_CIRCULAR, 54, 74 },
[DEX_AREA_ALTERING_CAVE] = { MARKER_CIRCULAR, 69, 73 },
[DEX_AREA_PATTERN_BUSH] = { MARKER_CIRCULAR, 76, 77 },
[DEX_AREA_DOTTED_HOLE] = { MARKER_CIRCULAR, 73, 95 },
[DEX_AREA_TANOBY_CHAMBER] = { MARKER_MED_H, 96, 90 },
};
static void Task_ShowAreaMarkers(u8 taskId)
{
struct PAM_TaskData * data = (void *)gTasks[taskId].data;
gSprites[data->spr_id].invisible = FALSE;
gSprites[data->spriteId].invisible = FALSE;
}
u8 Ctor_PokedexAreaMarkers(u16 species, u16 tilesTag, u8 palIdx, u8 y)
u8 CreatePokedexAreaMarkers(u16 species, u16 tilesTag, u8 palIdx, u8 y)
{
struct SpriteTemplate spriteTemplate;
struct CompressedSpriteSheet spriteSheet;
@@ -165,34 +196,42 @@ u8 Ctor_PokedexAreaMarkers(u16 species, u16 tilesTag, u8 palIdx, u8 y)
struct PAM_TaskData * data;
struct Subsprite * subsprites;
// Load gfx
spriteSheet.data = sMarkerTiles;
spriteSheet.size = 0x4A0;
spriteSheet.tag = tilesTag;
LoadCompressedSpriteSheet(&spriteSheet);
LoadPalette(sMarkerPal, 0x100 + 16 * palIdx, 0x20);
// Get marker subsprites
taskId = CreateTask(Task_ShowAreaMarkers, 0);
data = (void *)gTasks[taskId].data;
data->unk_0C = 0;
data->unused = 0;
data->tilesTag = tilesTag;
data->unk_10 = 0xFFFF;
data->paletteTag = TAG_NONE;
subsprites = Alloc(120 * sizeof(struct Subsprite));
data->buffer = subsprites;
data->subsprites.subsprites = subsprites;
data->subsprites.subspriteCount = BuildPokedexAreaSubspriteBuffer(species, subsprites);
data->subsprites.subspriteCount = GetSpeciesPokedexAreaMarkers(species, subsprites);
SetGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG0 | BLDCNT_TGT2_BG1 | BLDCNT_TGT2_BG2 | BLDCNT_TGT2_BG3 | BLDCNT_TGT2_BD);
SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(12, 8));
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_WININ, 0x1F1F);
SetGpuReg(REG_OFFSET_WINOUT, 0x2F3D);
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ);
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WIN01_BG2 | WINOUT_WIN01_BG3 | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_CLR);
// Set marker subsprites on full sprite
spriteTemplate = gDummySpriteTemplate;
spriteTemplate.tileTag = tilesTag;
data->spr_id = CreateSprite(&spriteTemplate, 104, y + 32, 0);
SetSubspriteTables(&gSprites[data->spr_id], &data->subsprites);
gSprites[data->spr_id].oam.objMode = ST_OAM_OBJ_WINDOW;
gSprites[data->spr_id].oam.paletteNum = palIdx;
gSprites[data->spr_id].subspriteTableNum = 0;
gSprites[data->spr_id].invisible = TRUE;
data->spriteId = CreateSprite(&spriteTemplate, 104, y + 32, 0);
SetSubspriteTables(&gSprites[data->spriteId], &data->subsprites);
gSprites[data->spriteId].oam.objMode = ST_OAM_OBJ_WINDOW;
gSprites[data->spriteId].oam.paletteNum = palIdx;
gSprites[data->spriteId].subspriteTableNum = 0;
gSprites[data->spriteId].invisible = TRUE;
// Show markers
HideBg(1);
SetBgAttribute(1, BG_ATTR_CHARBASEINDEX, 0);
FillBgTilemapBufferRect_Palette0(1, 0x00F, 0, 0, 30, 20);
@@ -201,17 +240,17 @@ u8 Ctor_PokedexAreaMarkers(u16 species, u16 tilesTag, u8 palIdx, u8 y)
return taskId;
}
void Dtor_PokedexAreaMarkers(u8 taskId)
void DestroyPokedexAreaMarkers(u8 taskId)
{
struct PAM_TaskData * data = (void *)gTasks[taskId].data;
FreeSpriteTilesByTag(data->tilesTag);
DestroySprite(&gSprites[data->spr_id]);
DestroySprite(&gSprites[data->spriteId]);
Free(data->buffer);
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_WININ, 0x1F1F);
SetGpuReg(REG_OFFSET_WINOUT, 0x1F1F);
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ);
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ);
ClearGpuRegBits(REG_OFFSET_DISPCNT, DISPCNT_OBJWIN_ON);
HideBg(1);
SetBgAttribute(1, BG_ATTR_CHARBASEINDEX, 2);
@@ -221,14 +260,14 @@ void Dtor_PokedexAreaMarkers(u8 taskId)
DestroyTask(taskId);
}
void SetAreaSubsprite(s32 i, s32 whichArea, struct Subsprite * subsprites)
void GetAreaMarkerSubsprite(s32 i, s32 dexArea, struct Subsprite * subsprites)
{
subsprites[i] = *sSubsprites[sSubspriteLookupTable[whichArea][0]];
subsprites[i].x = sSubspriteLookupTable[whichArea][1];
subsprites[i].y = sSubspriteLookupTable[whichArea][2];
subsprites[i] = *sSubsprites[sAreaMarkers[dexArea][0]];
subsprites[i].x = sAreaMarkers[dexArea][1];
subsprites[i].y = sAreaMarkers[dexArea][2];
}
u8 PokedexAreaMarkers_Any(u8 taskId)
u8 GetNumPokedexAreaMarkers(u8 taskId)
{
struct PAM_TaskData * data = (void *)gTasks[taskId].data;
return data->subsprites.subspriteCount;
+8 -4
View File
@@ -21,6 +21,8 @@
#include "pokedex_area_markers.h"
#include "field_specials.h"
#define TAG_AREA_MARKERS 2001
enum TextMode {
TEXT_LEFT,
TEXT_CENTER,
@@ -31,7 +33,8 @@ struct PokedexScreenData
{
u8 taskId;
u8 state;
u8 data[4];
u8 data[2];
u8 areaMarkersTaskId;
u32 unlockedCategories;
u32 modeSelectInput;
u16 modeSelectItemsAbove;
@@ -3123,9 +3126,10 @@ u8 DexScreen_DrawMonAreaPage(void)
}
// Create the area markers
sPokedexScreenData->data[2] = Ctor_PokedexAreaMarkers(species, 2001, 3, kantoMapVoff * 8);
if (!(PokedexAreaMarkers_Any(sPokedexScreenData->data[2])))
sPokedexScreenData->areaMarkersTaskId = CreatePokedexAreaMarkers(species, TAG_AREA_MARKERS, 3, kantoMapVoff * 8);
if (GetNumPokedexAreaMarkers(sPokedexScreenData->areaMarkersTaskId) == 0)
{
// No markers, display "Area Unknown"
BlitBitmapRectToWindow(sPokedexScreenData->windowIds[0], (void *)sBlitTiles_WideEllipse, 0, 0, 88, 16, 4, 28, 88, 16);
{
s32 strWidth = GetStringWidth(FONT_SMALL, gText_AreaUnknown, 0);
@@ -3149,7 +3153,7 @@ u8 DexScreen_DestroyAreaScreenResources(void)
{
int i;
Dtor_PokedexAreaMarkers(sPokedexScreenData->data[2]);
DestroyPokedexAreaMarkers(sPokedexScreenData->areaMarkersTaskId);
for (i = 0; i < 13; i++)
DexScreen_RemoveWindow(&sPokedexScreenData->windowIds[i]);
+2 -2
View File
@@ -2,12 +2,12 @@
#include "script.h"
#include "event_data.h"
#include "quest_log.h"
#include "mystery_gift.h"
#include "constants/maps.h"
#include "constants/map_scripts.h"
extern void ResetContextNpcTextColor(void); // field_specials
extern u16 CalcCRC16WithTable(u8 *data, int length); // util
extern bool32 ValidateReceivedWonderCard(void); // mevent
#define RAM_SCRIPT_MAGIC 51
@@ -554,7 +554,7 @@ bool32 ValidateRamScript(void)
u8 *GetSavedRamScriptIfValid(void)
{
struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data;
if (!ValidateReceivedWonderCard())
if (!ValidateSavedWonderCard())
return NULL;
if (scriptData->magic != RAM_SCRIPT_MAGIC)
return NULL;
+1 -1
View File
@@ -6,7 +6,7 @@
#include "trade.h"
#include "link.h"
#include "link_rfu.h"
#include "mevent.h"
#include "mystery_gift.h"
#include "graphics.h"
#include "strings.h"
#include "menu.h"
+1 -1
View File
@@ -20,7 +20,7 @@
#include "list_menu.h"
#include "load_save.h"
#include "menu.h"
#include "mevent.h"
#include "mystery_gift.h"
#include "mystery_gift_menu.h"
#include "new_menu_helpers.h"
#include "overworld.h"
+14 -13
View File
@@ -1,6 +1,7 @@
#include "global.h"
#include "link_rfu.h"
#include "mevent_server.h"
#include "mystery_gift_server.h"
#include "mystery_gift_client.h"
#include "constants/union_room.h"
ALIGNED(4) const u8 gText_UR_EmptyString[] = _("");
@@ -558,18 +559,18 @@ const u8 *const gTexts_UR_GladToMeetYou[GENDER_COUNT] = {
ALIGNED(4) const u8 gText_UR_FinishedCheckingPlayersTrainerCard[] = _("Finished checking {SPECIAL_F7 0x01}'s\nTRAINER CARD.{PAUSE 60}");
ALIGNED(4) static const u8 sText_CanceledReadingCard[] = _("Canceled reading the Card.");
static const struct mevent_client_cmd sClientScript_DynamicError[] = {
CLI_RECEIVE(0x15),
CLI_RECVBUF,
CLI_SENDALL,
CLI_RETURN(0x0e)
static const struct MysteryGiftClientCmd sClientScript_DynamicError[] = {
{CLI_RECV, MG_LINKID_DYNAMIC_MSG},
{CLI_COPY_MSG},
{CLI_SEND_READY_END},
{CLI_RETURN, CLI_MSG_BUFFER_FAILURE}
};
const struct mevent_server_cmd gServerScript_ClientCanceledCard[] = {
SRV_SEND(0x20, sClientScript_DynamicError),
SRV_WAITSND,
SRV_SENDSTR(0x1b, sText_CanceledReadingCard),
SRV_WAITSND,
SRV_RECV(0x14),
SRV_RETURN(0x09)
const struct MysteryGiftServerCmd gServerScript_ClientCanceledCard[] = {
{SVR_LOAD_CLIENT_SCRIPT, PTR_ARG(sClientScript_DynamicError)},
{SVR_SEND},
{SVR_LOAD_MSG, PTR_ARG(sText_CanceledReadingCard)},
{SVR_SEND},
{SVR_RECV, MG_LINKID_READY_END},
{SVR_RETURN, SVR_MSG_CLIENT_CANCELED}
};
+1 -1
View File
@@ -186,7 +186,7 @@ static u16 GetCurrentMapWildMonHeaderId(void)
gSaveBlock1Ptr->location.mapNum == MAP_NUM(SIX_ISLAND_ALTERING_CAVE))
{
u16 alteringCaveId = VarGet(VAR_ALTERING_CAVE_WILD_SET);
if (alteringCaveId > 8)
if (alteringCaveId >= NUM_ALTERING_CAVE_TABLES)
alteringCaveId = 0;
i += alteringCaveId;
+164 -154
View File
@@ -4,16 +4,11 @@
#include "wild_encounter.h"
#include "roamer.h"
#include "overworld.h"
#include "pokedex.h"
#include "pokedex_area_markers.h"
#include "constants/region_map_sections.h"
#include "constants/maps.h"
struct SeviiDexArea
{
const u16 (*lut)[2];
s32 count;
};
struct RoamerPair
{
u16 roamer;
@@ -21,137 +16,141 @@ struct RoamerPair
};
static s32 GetRoamerIndex(u16 species);
static s32 CountRoamerNests(u16 species, struct Subsprite * subsprites);
static bool32 PokemonInAnyEncounterTableInMap(const struct WildPokemonHeader * data, s32 species);
static bool32 PokemonInEncounterTable(const struct WildPokemonInfo * pokemon, s32 species, s32 count);
static s32 GetRoamerPokedexAreaMarkers(u16 species, struct Subsprite * subsprites);
static bool32 IsSpeciesOnMap(const struct WildPokemonHeader * data, s32 species);
static bool32 IsSpeciesInEncounterTable(const struct WildPokemonInfo * pokemon, s32 species, s32 count);
static u16 GetMapSecIdFromWildMonHeader(const struct WildPokemonHeader * header);
static bool32 TryGetMapSecPokedexAreaEntry(u16 mapSecId, const u16 (*lut)[2], s32 count, s32 * lutIdx_p, u16 * tableIdx_p);
static bool32 FindDexAreaByMapSec(u16 mapSecId, const u16 (*lut)[2], s32 count, s32 * lutIdx_p, u16 * tableIdx_p);
static const u16 sDexAreas_Kanto[][2] = {
{ MAPSEC_PALLET_TOWN, 1 },
{ MAPSEC_VIRIDIAN_CITY, 2 },
{ MAPSEC_PEWTER_CITY, 3 },
{ MAPSEC_CERULEAN_CITY, 4 },
{ MAPSEC_LAVENDER_TOWN, 5 },
{ MAPSEC_VERMILION_CITY, 6 },
{ MAPSEC_CELADON_CITY, 7 },
{ MAPSEC_FUCHSIA_CITY, 8 },
{ MAPSEC_CINNABAR_ISLAND, 9 },
{ MAPSEC_INDIGO_PLATEAU, 10 },
{ MAPSEC_SAFFRON_CITY, 11 },
{ MAPSEC_ROUTE_4_POKECENTER, 15 },
{ MAPSEC_ROUTE_10_POKECENTER, 21 },
{ MAPSEC_ROUTE_1, 12 },
{ MAPSEC_ROUTE_2, 13 },
{ MAPSEC_ROUTE_3, 14 },
{ MAPSEC_ROUTE_4, 15 },
{ MAPSEC_ROUTE_5, 16 },
{ MAPSEC_ROUTE_6, 17 },
{ MAPSEC_ROUTE_7, 18 },
{ MAPSEC_ROUTE_8, 19 },
{ MAPSEC_ROUTE_9, 20 },
{ MAPSEC_ROUTE_10, 21 },
{ MAPSEC_ROUTE_11, 22 },
{ MAPSEC_ROUTE_12, 23 },
{ MAPSEC_ROUTE_13, 24 },
{ MAPSEC_ROUTE_14, 25 },
{ MAPSEC_ROUTE_15, 26 },
{ MAPSEC_ROUTE_16, 27 },
{ MAPSEC_ROUTE_17, 28 },
{ MAPSEC_ROUTE_18, 29 },
{ MAPSEC_ROUTE_19, 30 },
{ MAPSEC_ROUTE_20, 31 },
{ MAPSEC_ROUTE_21, 32 },
{ MAPSEC_ROUTE_22, 33 },
{ MAPSEC_ROUTE_23, 34 },
{ MAPSEC_ROUTE_24, 35 },
{ MAPSEC_ROUTE_25, 36 },
{ MAPSEC_VIRIDIAN_FOREST, 37 },
{ MAPSEC_MT_MOON, 39 },
{ MAPSEC_S_S_ANNE, 6 },
{ MAPSEC_UNDERGROUND_PATH, 11 },
{ MAPSEC_UNDERGROUND_PATH_2, 11 },
{ MAPSEC_DIGLETTS_CAVE, 38 },
{ MAPSEC_KANTO_VICTORY_ROAD, 47 },
{ MAPSEC_ROCKET_HIDEOUT, 7 },
{ MAPSEC_SILPH_CO, 11 },
{ MAPSEC_POKEMON_MANSION, 46 },
{ MAPSEC_KANTO_SAFARI_ZONE, 44 },
{ MAPSEC_POKEMON_LEAGUE, 47 },
{ MAPSEC_ROCK_TUNNEL, 41 },
{ MAPSEC_SEAFOAM_ISLANDS, 45 },
{ MAPSEC_POKEMON_TOWER, 43 },
{ MAPSEC_CERULEAN_CAVE, 40 },
{ MAPSEC_POWER_PLANT, 42 }
{ MAPSEC_PALLET_TOWN, DEX_AREA_PALLET_TOWN },
{ MAPSEC_VIRIDIAN_CITY, DEX_AREA_VIRIDIAN_CITY },
{ MAPSEC_PEWTER_CITY, DEX_AREA_PEWTER_CITY },
{ MAPSEC_CERULEAN_CITY, DEX_AREA_CERULEAN_CITY },
{ MAPSEC_LAVENDER_TOWN, DEX_AREA_LAVENDER_TOWN },
{ MAPSEC_VERMILION_CITY, DEX_AREA_VERMILION_CITY },
{ MAPSEC_CELADON_CITY, DEX_AREA_CELADON_CITY },
{ MAPSEC_FUCHSIA_CITY, DEX_AREA_FUCHSIA_CITY },
{ MAPSEC_CINNABAR_ISLAND, DEX_AREA_CINNABAR_ISLAND },
{ MAPSEC_INDIGO_PLATEAU, DEX_AREA_INDIGO_PLATEAU },
{ MAPSEC_SAFFRON_CITY, DEX_AREA_SAFFRON_CITY },
{ MAPSEC_ROUTE_4_POKECENTER, DEX_AREA_ROUTE_4 },
{ MAPSEC_ROUTE_10_POKECENTER, DEX_AREA_ROUTE_10 },
{ MAPSEC_ROUTE_1, DEX_AREA_ROUTE_1 },
{ MAPSEC_ROUTE_2, DEX_AREA_ROUTE_2 },
{ MAPSEC_ROUTE_3, DEX_AREA_ROUTE_3 },
{ MAPSEC_ROUTE_4, DEX_AREA_ROUTE_4 },
{ MAPSEC_ROUTE_5, DEX_AREA_ROUTE_5 },
{ MAPSEC_ROUTE_6, DEX_AREA_ROUTE_6 },
{ MAPSEC_ROUTE_7, DEX_AREA_ROUTE_7 },
{ MAPSEC_ROUTE_8, DEX_AREA_ROUTE_8 },
{ MAPSEC_ROUTE_9, DEX_AREA_ROUTE_9 },
{ MAPSEC_ROUTE_10, DEX_AREA_ROUTE_10 },
{ MAPSEC_ROUTE_11, DEX_AREA_ROUTE_11 },
{ MAPSEC_ROUTE_12, DEX_AREA_ROUTE_12 },
{ MAPSEC_ROUTE_13, DEX_AREA_ROUTE_13 },
{ MAPSEC_ROUTE_14, DEX_AREA_ROUTE_14 },
{ MAPSEC_ROUTE_15, DEX_AREA_ROUTE_15 },
{ MAPSEC_ROUTE_16, DEX_AREA_ROUTE_16 },
{ MAPSEC_ROUTE_17, DEX_AREA_ROUTE_17 },
{ MAPSEC_ROUTE_18, DEX_AREA_ROUTE_18 },
{ MAPSEC_ROUTE_19, DEX_AREA_ROUTE_19 },
{ MAPSEC_ROUTE_20, DEX_AREA_ROUTE_20 },
{ MAPSEC_ROUTE_21, DEX_AREA_ROUTE_21 },
{ MAPSEC_ROUTE_22, DEX_AREA_ROUTE_22 },
{ MAPSEC_ROUTE_23, DEX_AREA_ROUTE_23 },
{ MAPSEC_ROUTE_24, DEX_AREA_ROUTE_24 },
{ MAPSEC_ROUTE_25, DEX_AREA_ROUTE_25 },
{ MAPSEC_VIRIDIAN_FOREST, DEX_AREA_VIRIDIAN_FOREST },
{ MAPSEC_MT_MOON, DEX_AREA_MT_MOON },
{ MAPSEC_S_S_ANNE, DEX_AREA_VERMILION_CITY },
{ MAPSEC_UNDERGROUND_PATH, DEX_AREA_SAFFRON_CITY },
{ MAPSEC_UNDERGROUND_PATH_2, DEX_AREA_SAFFRON_CITY },
{ MAPSEC_DIGLETTS_CAVE, DEX_AREA_DIGLETTS_CAVE },
{ MAPSEC_KANTO_VICTORY_ROAD, DEX_AREA_VICTORY_ROAD },
{ MAPSEC_ROCKET_HIDEOUT, DEX_AREA_CELADON_CITY },
{ MAPSEC_SILPH_CO, DEX_AREA_SAFFRON_CITY },
{ MAPSEC_POKEMON_MANSION, DEX_AREA_POKEMON_MANSION },
{ MAPSEC_KANTO_SAFARI_ZONE, DEX_AREA_SAFARI_ZONE },
{ MAPSEC_POKEMON_LEAGUE, DEX_AREA_VICTORY_ROAD },
{ MAPSEC_ROCK_TUNNEL, DEX_AREA_ROCK_TUNNEL },
{ MAPSEC_SEAFOAM_ISLANDS, DEX_AREA_SEAFOAM_ISLANDS },
{ MAPSEC_POKEMON_TOWER, DEX_AREA_POKEMON_TOWER },
{ MAPSEC_CERULEAN_CAVE, DEX_AREA_CERULEAN_CAVE },
{ MAPSEC_POWER_PLANT, DEX_AREA_POWER_PLANT }
};
static const u16 sDexAreas_Sevii1[][2] = {
{ MAPSEC_KINDLE_ROAD, 55 },
{ MAPSEC_TREASURE_BEACH, 56 },
{ MAPSEC_ONE_ISLAND, 48 },
{ MAPSEC_MT_EMBER, 72 }
{ MAPSEC_KINDLE_ROAD, DEX_AREA_KINDLE_ROAD },
{ MAPSEC_TREASURE_BEACH, DEX_AREA_TREASURE_BEACH },
{ MAPSEC_ONE_ISLAND, DEX_AREA_ONE_ISLAND },
{ MAPSEC_MT_EMBER, DEX_AREA_MT_EMBER }
};
static const u16 sDexAreas_Sevii2[][2] = {
{ MAPSEC_CAPE_BRINK, 57 },
{ MAPSEC_TWO_ISLAND, 49 }
{ MAPSEC_CAPE_BRINK, DEX_AREA_CAPE_BRINK },
{ MAPSEC_TWO_ISLAND, DEX_AREA_TWO_ISLAND }
};
static const u16 sDexAreas_Sevii3[][2] = {
{ MAPSEC_BOND_BRIDGE, 58 },
{ MAPSEC_THREE_ISLE_PORT, 59 },
{ MAPSEC_THREE_ISLAND, 50 },
{ MAPSEC_BERRY_FOREST, 73 },
{ MAPSEC_THREE_ISLE_PATH, 59 }
{ MAPSEC_BOND_BRIDGE, DEX_AREA_BOND_BRIDGE },
{ MAPSEC_THREE_ISLE_PORT, DEX_AREA_THREE_ISLE_PATH },
{ MAPSEC_THREE_ISLAND, DEX_AREA_THREE_ISLAND },
{ MAPSEC_BERRY_FOREST, DEX_AREA_BERRY_FOREST },
{ MAPSEC_THREE_ISLE_PATH, DEX_AREA_THREE_ISLE_PATH }
};
static const u16 sDexAreas_Sevii4[][2] = {
{ MAPSEC_FOUR_ISLAND, 51 },
{ MAPSEC_ICEFALL_CAVE, 74 }
{ MAPSEC_FOUR_ISLAND, DEX_AREA_FOUR_ISLAND },
{ MAPSEC_ICEFALL_CAVE, DEX_AREA_ICEFALL_CAVE }
};
static const u16 sDexAreas_Sevii5[][2] = {
{ MAPSEC_RESORT_GORGEOUS, 60 },
{ MAPSEC_WATER_LABYRINTH, 61 },
{ MAPSEC_FIVE_ISLE_MEADOW, 62 },
{ MAPSEC_MEMORIAL_PILLAR, 63 },
{ MAPSEC_FIVE_ISLAND, 52 },
{ MAPSEC_ROCKET_WAREHOUSE, 62 },
{ MAPSEC_LOST_CAVE, 75 }
{ MAPSEC_RESORT_GORGEOUS, DEX_AREA_RESORT_GORGEOUS },
{ MAPSEC_WATER_LABYRINTH, DEX_AREA_WATER_LABYRINTH },
{ MAPSEC_FIVE_ISLE_MEADOW, DEX_AREA_FIVE_ISLE_MEADOW },
{ MAPSEC_MEMORIAL_PILLAR, DEX_AREA_MEMORIAL_PILLAR },
{ MAPSEC_FIVE_ISLAND, DEX_AREA_FIVE_ISLAND },
{ MAPSEC_ROCKET_WAREHOUSE, DEX_AREA_FIVE_ISLE_MEADOW },
{ MAPSEC_LOST_CAVE, DEX_AREA_LOST_CAVE }
};
static const u16 sDexAreas_Sevii6[][2] = {
{ MAPSEC_OUTCAST_ISLAND, 64 },
{ MAPSEC_GREEN_PATH, 65 },
{ MAPSEC_WATER_PATH, 66 },
{ MAPSEC_RUIN_VALLEY, 67 },
{ MAPSEC_DOTTED_HOLE, 78 },
{ MAPSEC_PATTERN_BUSH, 77 },
{ MAPSEC_ALTERING_CAVE, 76 }
{ MAPSEC_OUTCAST_ISLAND, DEX_AREA_OUTCAST_ISLAND },
{ MAPSEC_GREEN_PATH, DEX_AREA_GREEN_PATH },
{ MAPSEC_WATER_PATH, DEX_AREA_WATER_PATH },
{ MAPSEC_RUIN_VALLEY, DEX_AREA_RUIN_VALLEY },
{ MAPSEC_DOTTED_HOLE, DEX_AREA_DOTTED_HOLE },
{ MAPSEC_PATTERN_BUSH, DEX_AREA_PATTERN_BUSH },
{ MAPSEC_ALTERING_CAVE, DEX_AREA_ALTERING_CAVE }
};
static const u16 sDexAreas_Sevii7[][2] = {
{ MAPSEC_TRAINER_TOWER, 68 },
{ MAPSEC_CANYON_ENTRANCE, 69 },
{ MAPSEC_SEVAULT_CANYON, 70 },
{ MAPSEC_TANOBY_RUINS, 71 },
{ MAPSEC_MONEAN_CHAMBER, 79 },
{ MAPSEC_LIPTOO_CHAMBER, 79 },
{ MAPSEC_WEEPTH_CHAMBER, 79 },
{ MAPSEC_DILFORD_CHAMBER, 79 },
{ MAPSEC_SCUFIB_CHAMBER, 79 },
{ MAPSEC_RIXY_CHAMBER, 79 },
{ MAPSEC_VIAPOIS_CHAMBER, 79 }
{ MAPSEC_TRAINER_TOWER, DEX_AREA_TRAINER_TOWER },
{ MAPSEC_CANYON_ENTRANCE, DEX_AREA_CANYON_ENTRANCE },
{ MAPSEC_SEVAULT_CANYON, DEX_AREA_SEVAULT_CANYON },
{ MAPSEC_TANOBY_RUINS, DEX_AREA_TANOBY_RUINS },
{ MAPSEC_MONEAN_CHAMBER, DEX_AREA_TANOBY_CHAMBER },
{ MAPSEC_LIPTOO_CHAMBER, DEX_AREA_TANOBY_CHAMBER },
{ MAPSEC_WEEPTH_CHAMBER, DEX_AREA_TANOBY_CHAMBER },
{ MAPSEC_DILFORD_CHAMBER, DEX_AREA_TANOBY_CHAMBER },
{ MAPSEC_SCUFIB_CHAMBER, DEX_AREA_TANOBY_CHAMBER },
{ MAPSEC_RIXY_CHAMBER, DEX_AREA_TANOBY_CHAMBER },
{ MAPSEC_VIAPOIS_CHAMBER, DEX_AREA_TANOBY_CHAMBER }
};
static const struct SeviiDexArea sSeviiDexAreas[] = {
{ sDexAreas_Sevii1, 4 },
{ sDexAreas_Sevii2, 2 },
{ sDexAreas_Sevii3, 5 },
{ sDexAreas_Sevii4, 2 },
{ sDexAreas_Sevii5, 7 },
{ sDexAreas_Sevii6, 7 },
{ sDexAreas_Sevii7, 11 }
static const struct
{
const u16 (*table)[2];
s32 count;
} sSeviiDexAreas[] = {
{ sDexAreas_Sevii1, ARRAY_COUNT(sDexAreas_Sevii1) },
{ sDexAreas_Sevii2, ARRAY_COUNT(sDexAreas_Sevii2) },
{ sDexAreas_Sevii3, ARRAY_COUNT(sDexAreas_Sevii3) },
{ sDexAreas_Sevii4, ARRAY_COUNT(sDexAreas_Sevii4) },
{ sDexAreas_Sevii5, ARRAY_COUNT(sDexAreas_Sevii5) },
{ sDexAreas_Sevii6, ARRAY_COUNT(sDexAreas_Sevii6) },
{ sDexAreas_Sevii7, ARRAY_COUNT(sDexAreas_Sevii7) }
};
static const struct RoamerPair sRoamerPairs[] = {
@@ -160,27 +159,27 @@ static const struct RoamerPair sRoamerPairs[] = {
{ SPECIES_RAIKOU, SPECIES_SQUIRTLE }
};
s32 BuildPokedexAreaSubspriteBuffer(u16 species, struct Subsprite * subsprites)
// Scans for the given species and populates 'subsprites' with the area markers.
// Returns the number of areas where the species was found.
s32 GetSpeciesPokedexAreaMarkers(u16 species, struct Subsprite * subsprites)
{
s32 areaCount;
s32 j;
s32 mapSecId;
u16 dexAreaSubspriteIdx;
s32 dexAreaEntryLUTidx;
u16 dexArea;
s32 tableIndex;
s32 seviiAreas;
s32 alteringCaveCount;
s32 alteringCaveNum;
s32 i;
if (GetRoamerIndex(species) >= SPECIES_NONE)
{
return CountRoamerNests(species, subsprites);
}
if (GetRoamerIndex(species) >= 0)
return GetRoamerPokedexAreaMarkers(species, subsprites);
seviiAreas = GetUnlockedSeviiAreas();
alteringCaveCount = 0;
alteringCaveNum = VarGet(VAR_ALTERING_CAVE_WILD_SET);
if (alteringCaveNum > 8)
if (alteringCaveNum >= NUM_ALTERING_CAVE_TABLES)
alteringCaveNum = 0;
for (i = 0, areaCount = 0; gWildMonHeaders[i].mapGroup != MAP_GROUP(UNDEFINED); i++)
{
@@ -191,27 +190,27 @@ s32 BuildPokedexAreaSubspriteBuffer(u16 species, struct Subsprite * subsprites)
if (alteringCaveNum != alteringCaveCount - 1)
continue;
}
if (PokemonInAnyEncounterTableInMap(&gWildMonHeaders[i], species))
if (IsSpeciesOnMap(&gWildMonHeaders[i], species))
{
dexAreaEntryLUTidx = 0;
while (TryGetMapSecPokedexAreaEntry(mapSecId, sDexAreas_Kanto, 55, &dexAreaEntryLUTidx, &dexAreaSubspriteIdx))
// Search for all dex areas associated with this MAPSEC.
// In the vanilla game each MAPSEC only has at most one DEX_AREA.
tableIndex = 0;
while (FindDexAreaByMapSec(mapSecId, sDexAreas_Kanto, ARRAY_COUNT(sDexAreas_Kanto), &tableIndex, &dexArea))
{
if (dexAreaSubspriteIdx != 0)
{
SetAreaSubsprite(areaCount++, dexAreaSubspriteIdx, subsprites);
}
if (dexArea != DEX_AREA_NONE)
GetAreaMarkerSubsprite(areaCount++, dexArea, subsprites);
}
for (j = 0; j < NELEMS(sSeviiDexAreas); j++)
for (j = 0; j < ARRAY_COUNT(sSeviiDexAreas); j++)
{
if ((seviiAreas >> j) & 1)
{
dexAreaEntryLUTidx = 0;
while (TryGetMapSecPokedexAreaEntry(mapSecId, sSeviiDexAreas[j].lut, sSeviiDexAreas[j].count, &dexAreaEntryLUTidx, &dexAreaSubspriteIdx))
// Search for all dex areas associated with this MAPSEC in this unlocked Sevii Island
tableIndex = 0;
while (FindDexAreaByMapSec(mapSecId, sSeviiDexAreas[j].table, sSeviiDexAreas[j].count, &tableIndex, &dexArea))
{
if (dexAreaSubspriteIdx != 0)
{
SetAreaSubsprite(areaCount++, dexAreaSubspriteIdx, subsprites);
}
if (dexArea != DEX_AREA_NONE)
GetAreaMarkerSubsprite(areaCount++, dexArea, subsprites);
}
}
}
@@ -224,7 +223,7 @@ s32 BuildPokedexAreaSubspriteBuffer(u16 species, struct Subsprite * subsprites)
static s32 GetRoamerIndex(u16 species)
{
s32 i;
for (i = 0; i < NELEMS(sRoamerPairs); i++)
for (i = 0; i < ARRAY_COUNT(sRoamerPairs); i++)
{
if (sRoamerPairs[i].roamer == species)
return i;
@@ -233,46 +232,54 @@ static s32 GetRoamerIndex(u16 species)
return -1;
}
static s32 CountRoamerNests(u16 species, struct Subsprite * subsprites)
static s32 GetRoamerPokedexAreaMarkers(u16 species, struct Subsprite * subsprites)
{
u16 roamerLocation;
u16 mapSecId;
s32 roamerIdx;
u16 dexAreaSubspriteIdx;
s32 dexAreaEntryLUTidx;
u16 dexArea;
s32 tableIndex;
// Make sure that this is a roamer species, and that it corresponds to the player's starter.
roamerIdx = GetRoamerIndex(species);
if (roamerIdx < 0)
return 0;
if (sRoamerPairs[roamerIdx].starter != GetStarterSpecies())
return 0;
roamerLocation = GetRoamerLocationMapSectionId();
dexAreaEntryLUTidx = 0;
if (TryGetMapSecPokedexAreaEntry(roamerLocation, sDexAreas_Kanto, 55, &dexAreaEntryLUTidx, &dexAreaSubspriteIdx))
mapSecId = GetRoamerLocationMapSectionId();
tableIndex = 0;
if (FindDexAreaByMapSec(mapSecId, sDexAreas_Kanto, ARRAY_COUNT(sDexAreas_Kanto), &tableIndex, &dexArea))
{
if (dexAreaSubspriteIdx != 0)
if (dexArea != DEX_AREA_NONE)
{
SetAreaSubsprite(0, dexAreaSubspriteIdx, subsprites);
GetAreaMarkerSubsprite(0, dexArea, subsprites);
return 1;
}
}
return 0;
}
static bool32 PokemonInAnyEncounterTableInMap(const struct WildPokemonHeader * data, s32 species)
static bool32 IsSpeciesOnMap(const struct WildPokemonHeader * data, s32 species)
{
if (PokemonInEncounterTable(data->landMonsInfo, species, 12))
if (IsSpeciesInEncounterTable(data->landMonsInfo, species, LAND_WILD_COUNT))
return TRUE;
if (PokemonInEncounterTable(data->waterMonsInfo, species, 5))
if (IsSpeciesInEncounterTable(data->waterMonsInfo, species, WATER_WILD_COUNT))
return TRUE;
if (PokemonInEncounterTable(data->fishingMonsInfo, species, 12)) // 10
// When searching the fishing encounters, this incorrectly uses the size of the land encounters.
// As a result it's reading out of bounds of the fishing encounters tables.
#ifdef BUGFIX
if (IsSpeciesInEncounterTable(data->fishingMonsInfo, species, FISH_WILD_COUNT))
#else
if (IsSpeciesInEncounterTable(data->fishingMonsInfo, species, LAND_WILD_COUNT))
#endif
return TRUE;
if (PokemonInEncounterTable(data->rockSmashMonsInfo, species, 5))
if (IsSpeciesInEncounterTable(data->rockSmashMonsInfo, species, ROCK_WILD_COUNT))
return TRUE;
return FALSE;
}
static bool32 PokemonInEncounterTable(const struct WildPokemonInfo * info, s32 species, s32 count)
static bool32 IsSpeciesInEncounterTable(const struct WildPokemonInfo * info, s32 species, s32 count)
{
s32 i;
if (info != NULL)
@@ -291,15 +298,18 @@ static u16 GetMapSecIdFromWildMonHeader(const struct WildPokemonHeader * header)
return Overworld_GetMapHeaderByGroupAndId(header->mapGroup, header->mapNum)->regionMapSectionId;
}
static bool32 TryGetMapSecPokedexAreaEntry(u16 mapSecId, const u16 (*lut)[2], s32 count, s32 * lutIdx_p, u16 * tableIdx_p)
// Search a MAPSEC -> DEX_AREA table for the given mapsec.
// Assigns the DEX_AREA (if found) to 'dexArea', and the first unread table index to 'index'.
// Returns TRUE if DEX_AREA was found, FALSE otherwise.
static bool32 FindDexAreaByMapSec(u16 mapSecId, const u16 (*table)[2], s32 count, s32 * index, u16 * dexArea)
{
s32 i;
for (i = *lutIdx_p; i < count; i++)
for (i = *index; i < count; i++)
{
if (lut[i][0] == mapSecId)
if (table[i][0] == mapSecId)
{
*tableIdx_p = lut[i][1];
*lutIdx_p = i + 1;
*dexArea = table[i][1];
*index = i + 1;
return TRUE;
}
}
+154
View File
@@ -0,0 +1,154 @@
#include "global.h"
#include "mystery_gift.h"
#include "random.h"
#include "event_data.h"
#include "wonder_news.h"
#include "constants/items.h"
// Every 4th reward for sending Wonder News to a link partner is a "big" reward.
#define MAX_SENT_REWARD 4
// Only up to 5 rewards can be received in a short period. After this the player
// must take 500 steps before any more rewards can be received.
#define MAX_REWARD 5
static u32 GetRewardItem(struct WonderNewsMetadata *);
static u32 GetRewardType(struct WonderNewsMetadata *);
static void IncrementRewardCounter(struct WonderNewsMetadata *);
static void IncrementSentRewardCounter(struct WonderNewsMetadata *);
static void ResetSentRewardCounter(struct WonderNewsMetadata *);
void WonderNews_SetReward(u32 newsType)
{
struct WonderNewsMetadata *data = GetSavedWonderNewsMetadata();
data->newsType = newsType;
switch (newsType)
{
case WONDER_NEWS_NONE:
break;
case WONDER_NEWS_RECV_FRIEND:
case WONDER_NEWS_RECV_WIRELESS:
// Random berry between ITEM_RAZZ_BERRY and ITEM_NOMEL_BERRY
data->berry = (Random() % 15) + ITEM_TO_BERRY(ITEM_RAZZ_BERRY);
break;
case WONDER_NEWS_SENT:
// Random berry between ITEM_CHERI_BERRY and ITEM_IAPAPA_BERRY
data->berry = (Random() % 15) + ITEM_TO_BERRY(ITEM_CHERI_BERRY);
break;
}
}
void WonderNews_Reset(void)
{
struct WonderNewsMetadata *data = GetSavedWonderNewsMetadata();
data->newsType = WONDER_NEWS_NONE;
data->sentRewardCounter = 0;
data->rewardCounter = 0;
data->berry = 0;
VarSet(VAR_WONDER_NEWS_STEP_COUNTER, 0);
}
void WonderNews_IncrementStepCounter(void)
{
u16 *stepCounter = GetVarPointer(VAR_WONDER_NEWS_STEP_COUNTER);
struct WonderNewsMetadata *data = GetSavedWonderNewsMetadata();
// If the player has reached the reward limit, start counting steps.
// When they reach 500 steps reset the reward counter to allow them to
// receive rewards again.
if (data->rewardCounter >= MAX_REWARD && ++(*stepCounter) >= 500)
{
data->rewardCounter = 0;
*stepCounter = 0;
}
}
u16 WonderNews_GetRewardInfo(void)
{
u16 *result = &gSpecialVar_Result;
struct WonderNewsMetadata *data = GetSavedWonderNewsMetadata();
u16 rewardType;
if (!IsMysteryGiftEnabled() || !ValidateSavedWonderNews())
return NEWS_REWARD_NONE;
rewardType = GetRewardType(data);
switch (rewardType)
{
case NEWS_REWARD_RECV_SMALL:
case NEWS_REWARD_RECV_BIG:
*result = GetRewardItem(data);
break;
case NEWS_REWARD_SENT_SMALL:
*result = GetRewardItem(data);
IncrementSentRewardCounter(data);
break;
case NEWS_REWARD_SENT_BIG:
*result = GetRewardItem(data);
ResetSentRewardCounter(data);
break;
case NEWS_REWARD_NONE:
case NEWS_REWARD_WAITING:
case NEWS_REWARD_AT_MAX:
break;
}
return rewardType;
}
static u32 GetRewardItem(struct WonderNewsMetadata *data)
{
u32 itemId;
data->newsType = WONDER_NEWS_NONE;
itemId = data->berry + FIRST_BERRY_INDEX - 1;
data->berry = 0;
IncrementRewardCounter(data);
return itemId;
}
static void ResetSentRewardCounter(struct WonderNewsMetadata *data)
{
data->sentRewardCounter = 0;
}
// Track number of times a reward was received (or attmepted to receive) for sending Wonder News to a link partner.
static void IncrementSentRewardCounter(struct WonderNewsMetadata *data)
{
data->sentRewardCounter++;
if (data->sentRewardCounter > MAX_SENT_REWARD)
data->sentRewardCounter = MAX_SENT_REWARD;
}
static void IncrementRewardCounter(struct WonderNewsMetadata *data)
{
data->rewardCounter++;
if (data->rewardCounter > MAX_REWARD)
data->rewardCounter = MAX_REWARD;
}
static u32 GetRewardType(struct WonderNewsMetadata *data)
{
if (data->rewardCounter == MAX_REWARD)
return NEWS_REWARD_AT_MAX;
switch (data->newsType)
{
case WONDER_NEWS_NONE:
return NEWS_REWARD_WAITING;
case WONDER_NEWS_RECV_FRIEND:
return NEWS_REWARD_RECV_SMALL;
case WONDER_NEWS_RECV_WIRELESS:
return NEWS_REWARD_RECV_BIG;
case WONDER_NEWS_SENT:
if (data->sentRewardCounter < MAX_SENT_REWARD - 1)
return NEWS_REWARD_SENT_SMALL;
return NEWS_REWARD_SENT_BIG;
default:
AGB_ASSERT_EX(0, ABSPATH("menews_jisan.c"), 383);
return NEWS_REWARD_NONE;
}
}