import from github
This commit is contained in:
1312
src/apprentice.c
Normal file
1312
src/apprentice.c
Normal file
@ -0,0 +1,1312 @@
|
||||
#include "global.h"
|
||||
#include "apprentice.h"
|
||||
#include "battle.h"
|
||||
#include "battle_tower.h"
|
||||
#include "data.h"
|
||||
#include "event_data.h"
|
||||
#include "event_object_movement.h"
|
||||
#include "field_player_avatar.h"
|
||||
#include "international_string_util.h"
|
||||
#include "item.h"
|
||||
#include "item_menu.h"
|
||||
#include "main.h"
|
||||
#include "malloc.h"
|
||||
#include "menu.h"
|
||||
#include "new_game.h"
|
||||
#include "party_menu.h"
|
||||
#include "random.h"
|
||||
#include "script.h"
|
||||
#include "script_menu.h"
|
||||
#include "sound.h"
|
||||
#include "string_util.h"
|
||||
#include "strings.h"
|
||||
#include "task.h"
|
||||
#include "text.h"
|
||||
#include "constants/battle_frontier.h"
|
||||
#include "constants/easy_chat.h"
|
||||
#include "constants/items.h"
|
||||
#include "constants/pokemon.h"
|
||||
#include "constants/songs.h"
|
||||
#include "constants/trainers.h"
|
||||
#include "constants/moves.h"
|
||||
|
||||
/* Summary of Apprentice, because (as of writing at least) it's not very well documented online
|
||||
*
|
||||
* ## Basic info
|
||||
* In the Battle Tower lobby there is an NPC which asks to be taught by the player
|
||||
* They can be any 1 of 16 NPC trainers, each with their own name, class, and set of possible party species
|
||||
* They ask the player a series of questions once per day, and eventually depart the lobby to be replaced by a new Apprentice
|
||||
*
|
||||
* ## Initial Questions
|
||||
* The first question they always ask is a request to be taught, which cannot be rejected
|
||||
* The second question (which follows immediately after) is whether they should participate in Battle Tower Lv 50 or Open Lv
|
||||
* After these opening questions they always ask the player to choose between 2 mons, which they repeat 3 times
|
||||
*
|
||||
* ## Random Questions
|
||||
* After choosing 3 mons for them, the Apprentice will randomly ask between 1 and 8 questions of 4 different types, as follows
|
||||
* - Asking which mon to lead with, which they will only ask at most once
|
||||
* - Asking which move a mon should use, which they will ask at most 5 times
|
||||
* - Asking what held item to give to a mon, which they will ask at most 3 times (once for each mon)
|
||||
* - Asking what they should say when they win a battle, which will always be their final question before departing
|
||||
*
|
||||
* ## After departing
|
||||
* After telling them what they should say when they win a battle they will leave the lobby for a final time
|
||||
* They will then be replaced by a new random Apprentice (they can repeat)
|
||||
* Up to 4 old Apprentices are saved and can be encountered (or partnered with) during challenges of the mode they were told to battle in
|
||||
* They can also be record mixed to and from other Emerald games
|
||||
* Old/record mixed Apprentices are stored in struct Apprentice apprentices of SaveBlock2
|
||||
* and the current Apprentice is stored in struct PlayersApprentice playerApprentice of SaveBlock2
|
||||
*/
|
||||
|
||||
#define PLAYER_APPRENTICE gSaveBlock2Ptr->playerApprentice
|
||||
#define CURRENT_QUESTION_NUM PLAYER_APPRENTICE.questionsAnswered - NUM_WHICH_MON_QUESTIONS
|
||||
|
||||
struct ApprenticePartyMovesData
|
||||
{
|
||||
u8 moveCounter;
|
||||
u16 moves[MULTI_PARTY_SIZE][NUM_WHICH_MOVE_QUESTIONS];
|
||||
u8 moveSlots[MULTI_PARTY_SIZE][NUM_WHICH_MOVE_QUESTIONS];
|
||||
};
|
||||
|
||||
struct ApprenticeQuestionData
|
||||
{
|
||||
u16 speciesId;
|
||||
u16 altSpeciesId;
|
||||
u16 moveId1;
|
||||
u16 moveId2;
|
||||
};
|
||||
|
||||
// IWRAM common
|
||||
struct ApprenticePartyMovesData *gApprenticePartyMovesData;
|
||||
struct ApprenticeQuestionData *gApprenticeQuestionData;
|
||||
void (*gApprenticeFunc)(void);
|
||||
|
||||
// This file's functions.
|
||||
static u16 GetRandomAlternateMove(u8 monId);
|
||||
static bool8 TrySetMove(u8 monId, u16 moveId);
|
||||
static void CreateChooseAnswerTask(bool8 noBButton, u8 itemsCount, u8 windowId);
|
||||
static u8 CreateAndShowWindow(u8 left, u8 top, u8 width, u8 height);
|
||||
static void RemoveAndHideWindow(u8 windowId);
|
||||
static void ExecuteFuncAfterButtonPress(void (*func)(void));
|
||||
|
||||
static void Script_GivenApprenticeLvlMode(void);
|
||||
static void Script_SetApprenticeLvlMode(void);
|
||||
static void Script_SetApprenticeId(void);
|
||||
static void ShuffleApprenticeSpecies(void);
|
||||
static void Script_SetRandomQuestionData(void);
|
||||
static void IncrementQuestionsAnswered(void);
|
||||
static void IsFinalQuestion(void);
|
||||
static void Script_CreateApprenticeMenu(void);
|
||||
static void Script_PrintApprenticeMessage(void);
|
||||
static void Script_ResetPlayerApprentice(void);
|
||||
static void GetShouldCheckApprenticeGone(void);
|
||||
static void ApprenticeGetQuestion(void);
|
||||
static void GetNumApprenticePartyMonsAssigned(void);
|
||||
static void SetApprenticePartyMon(void);
|
||||
static void InitQuestionData(void);
|
||||
static void FreeQuestionData(void);
|
||||
static void ApprenticeBufferString(void);
|
||||
static void SetApprenticeMonMove(void);
|
||||
static void SetLeadApprenticeMon(void);
|
||||
static void Script_ApprenticeOpenBagMenu(void);
|
||||
static void TrySetApprenticeHeldItem(void);
|
||||
static void SaveApprentice(void);
|
||||
static void SetSavedApprenticeTrainerGfxId(void);
|
||||
static void SetPlayerApprenticeTrainerGfxId(void);
|
||||
static void GetShouldApprenticeLeave(void);
|
||||
static void ShiftSavedApprentices(void);
|
||||
|
||||
#include "data/battle_frontier/apprentice.h"
|
||||
|
||||
void BufferApprenticeChallengeText(u8 saveApprenticeId)
|
||||
{
|
||||
u8 i, num;
|
||||
const u8 *challengeText;
|
||||
|
||||
num = gSaveBlock2Ptr->apprentices[saveApprenticeId].number;
|
||||
for (i = 0; num != 0 && i < APPRENTICE_COUNT; num /= 10, i++)
|
||||
;
|
||||
|
||||
StringCopy_PlayerName(gStringVar1, gSaveBlock2Ptr->apprentices[saveApprenticeId].playerName);
|
||||
ConvertInternationalString(gStringVar1, gSaveBlock2Ptr->apprentices[saveApprenticeId].language);
|
||||
ConvertIntToDecimalStringN(gStringVar2, gSaveBlock2Ptr->apprentices[saveApprenticeId].number, STR_CONV_MODE_RIGHT_ALIGN, i);
|
||||
challengeText = sApprenticeChallengeTexts[gSaveBlock2Ptr->apprentices[saveApprenticeId].id];
|
||||
StringExpandPlaceholders(gStringVar4, challengeText);
|
||||
}
|
||||
|
||||
void Apprentice_EnableBothScriptContexts(void)
|
||||
{
|
||||
EnableBothScriptContexts();
|
||||
}
|
||||
|
||||
void ResetApprenticeStruct(struct Apprentice *apprentice)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(apprentice->speechWon); i++)
|
||||
apprentice->speechWon[i] = EC_EMPTY_WORD;
|
||||
|
||||
apprentice->playerName[0] = EOS;
|
||||
apprentice->id = NUM_APPRENTICES;
|
||||
}
|
||||
|
||||
void ResetAllApprenticeData(void)
|
||||
{
|
||||
u8 i, j;
|
||||
|
||||
PLAYER_APPRENTICE.saveId = 0;
|
||||
for (i = 0; i < APPRENTICE_COUNT; i++)
|
||||
{
|
||||
for (j = 0; j < ARRAY_COUNT(gSaveBlock2Ptr->apprentices[i].speechWon); j++)
|
||||
gSaveBlock2Ptr->apprentices[i].speechWon[j] = EC_EMPTY_WORD;
|
||||
gSaveBlock2Ptr->apprentices[i].id = NUM_APPRENTICES;
|
||||
gSaveBlock2Ptr->apprentices[i].playerName[0] = EOS;
|
||||
gSaveBlock2Ptr->apprentices[i].lvlMode = 0;
|
||||
gSaveBlock2Ptr->apprentices[i].number = 0;
|
||||
gSaveBlock2Ptr->apprentices[i].numQuestions = 0;
|
||||
for (j = 0; j < TRAINER_ID_LENGTH; j++)
|
||||
gSaveBlock2Ptr->apprentices[i].playerId[j] = 0;
|
||||
gSaveBlock2Ptr->apprentices[i].language = gGameLanguage;
|
||||
gSaveBlock2Ptr->apprentices[i].checksum = 0;
|
||||
}
|
||||
|
||||
Script_ResetPlayerApprentice();
|
||||
}
|
||||
|
||||
static bool8 GivenApprenticeLvlMode(void)
|
||||
{
|
||||
return (PLAYER_APPRENTICE.lvlMode != 0);
|
||||
}
|
||||
|
||||
static void SetApprenticeId(void)
|
||||
{
|
||||
if (gSaveBlock2Ptr->apprentices[0].number == 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
PLAYER_APPRENTICE.id = sInitialApprenticeIds[Random() % ARRAY_COUNT(sInitialApprenticeIds)];
|
||||
} while (PLAYER_APPRENTICE.id == gSaveBlock2Ptr->apprentices[0].id);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
PLAYER_APPRENTICE.id = Random() % (NUM_APPRENTICES);
|
||||
} while (PLAYER_APPRENTICE.id == gSaveBlock2Ptr->apprentices[0].id);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetPlayersApprenticeLvlMode(u8 mode)
|
||||
{
|
||||
PLAYER_APPRENTICE.lvlMode = mode;
|
||||
}
|
||||
|
||||
static void ShuffleApprenticeSpecies(void)
|
||||
{
|
||||
u8 species[APPRENTICE_SPECIES_COUNT];
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(species); i++)
|
||||
species[i] = i;
|
||||
|
||||
// Shuffle the possible species an arbitrary 50 times
|
||||
for (i = 0; i < 50; i++)
|
||||
{
|
||||
u8 temp;
|
||||
u8 rand1 = Random() % ARRAY_COUNT(species);
|
||||
u8 rand2 = Random() % ARRAY_COUNT(species);
|
||||
SWAP(species[rand1], species[rand2], temp);
|
||||
}
|
||||
|
||||
for (i = 0; i < MULTI_PARTY_SIZE; i++)
|
||||
PLAYER_APPRENTICE.speciesIds[i] = ((species[i * 2] & 0xF) << 4) | ((species[i * 2 + 1]) & 0xF);
|
||||
}
|
||||
|
||||
// Pick one of the Apprentice's mons to ask the question about
|
||||
// Picking a move chooses a random mon, picking a held item is sequential (so that none are repeated)
|
||||
static u8 GetMonIdForQuestion(u8 questionId, u8 *party, u8 *partySlot)
|
||||
{
|
||||
u8 i, count;
|
||||
u8 monId = 0;
|
||||
|
||||
if (questionId == QUESTION_ID_WHICH_MOVE)
|
||||
{
|
||||
do
|
||||
{
|
||||
monId = Random() % (MULTI_PARTY_SIZE);
|
||||
for (count = 0, i = 0; i < NUM_WHICH_MOVE_QUESTIONS; i++)
|
||||
{
|
||||
if (gApprenticePartyMovesData->moves[monId][i] != MOVE_NONE)
|
||||
count++;
|
||||
}
|
||||
} while (count > MULTI_PARTY_SIZE);
|
||||
}
|
||||
else if (questionId == QUESTION_ID_WHAT_ITEM)
|
||||
{
|
||||
monId = party[*partySlot];
|
||||
(*partySlot)++;
|
||||
}
|
||||
|
||||
return monId;
|
||||
}
|
||||
|
||||
// Sets the random order and data for the remaining questions after the initial "choose mon" questions
|
||||
static void SetRandomQuestionData(void)
|
||||
{
|
||||
u8 questionOrder[APPRENTICE_MAX_QUESTIONS + 1];
|
||||
u8 partyOrder[MULTI_PARTY_SIZE];
|
||||
u8 partySlot;
|
||||
u8 i, j;
|
||||
u8 rand1, rand2;
|
||||
u8 id;
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(partyOrder); i++)
|
||||
partyOrder[i] = i;
|
||||
|
||||
// Shuffle the party an arbitrary 10 times
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
u8 temp;
|
||||
rand1 = Random() % ARRAY_COUNT(partyOrder);
|
||||
rand2 = Random() % ARRAY_COUNT(partyOrder);
|
||||
SWAP(partyOrder[rand1], partyOrder[rand2], temp);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(questionOrder); i++)
|
||||
questionOrder[i] = sQuestionPossibilities[i];
|
||||
|
||||
// Shuffle the questions an arbitrary 50 times
|
||||
for (i = 0; i < 50; i++)
|
||||
{
|
||||
u8 temp;
|
||||
rand1 = Random() % ARRAY_COUNT(questionOrder);
|
||||
rand2 = Random() % ARRAY_COUNT(questionOrder);
|
||||
SWAP(questionOrder[rand1], questionOrder[rand2], temp);
|
||||
}
|
||||
|
||||
gApprenticePartyMovesData = AllocZeroed(sizeof(*gApprenticePartyMovesData));
|
||||
gApprenticePartyMovesData->moveCounter = 0;
|
||||
for (i = 0; i < NUM_WHICH_MOVE_QUESTIONS; i++)
|
||||
{
|
||||
for (j = 0; j < MULTI_PARTY_SIZE; j++)
|
||||
gApprenticePartyMovesData->moveSlots[j][i] = MAX_MON_MOVES;
|
||||
}
|
||||
|
||||
partySlot = 0;
|
||||
for (i = 0; i < APPRENTICE_MAX_QUESTIONS; i++)
|
||||
{
|
||||
PLAYER_APPRENTICE.questions[i].questionId = questionOrder[i];
|
||||
if (questionOrder[i] != QUESTION_ID_WHICH_FIRST)
|
||||
{
|
||||
PLAYER_APPRENTICE.questions[i].monId = GetMonIdForQuestion(questionOrder[i], partyOrder, &partySlot);
|
||||
id = PLAYER_APPRENTICE.questions[i].monId;
|
||||
if (questionOrder[i] == QUESTION_ID_WHICH_MOVE)
|
||||
{
|
||||
do
|
||||
{
|
||||
rand1 = Random() % MAX_MON_MOVES;
|
||||
for (j = 0; j < gApprenticePartyMovesData->moveCounter + 1; j++)
|
||||
{
|
||||
if (gApprenticePartyMovesData->moveSlots[id][j] == rand1)
|
||||
break;
|
||||
}
|
||||
} while (j != gApprenticePartyMovesData->moveCounter + 1);
|
||||
|
||||
gApprenticePartyMovesData->moveSlots[id][gApprenticePartyMovesData->moveCounter] = rand1;
|
||||
PLAYER_APPRENTICE.questions[i].moveSlot = rand1;
|
||||
PLAYER_APPRENTICE.questions[i].data = GetRandomAlternateMove(PLAYER_APPRENTICE.questions[i].monId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FREE_AND_SET_NULL(gApprenticePartyMovesData);
|
||||
}
|
||||
|
||||
#define APPRENTICE_SPECIES_ID(monId) \
|
||||
((monId < MULTI_PARTY_SIZE) ? (PLAYER_APPRENTICE.speciesIds[monId] >> (((PLAYER_APPRENTICE.party >> monId) & 1) << 2) & 0xF) : 0)
|
||||
|
||||
#define APPRENTICE_SPECIES_ID_NO_COND(monId, count) \
|
||||
monId = ((PLAYER_APPRENTICE.party >> count) & 1); \
|
||||
monId = ((PLAYER_APPRENTICE.speciesIds[count]) >> (monId << 2)) & 0xF; \
|
||||
|
||||
// Get the second move choice for the "Which move" question
|
||||
// Unlike the first move choice, this can be either a level up move or a TM/HM move
|
||||
static u16 GetRandomAlternateMove(u8 monId)
|
||||
{
|
||||
u8 i, j;
|
||||
u8 id;
|
||||
u8 numLearnsetMoves;
|
||||
u16 species;
|
||||
const u16 *learnset;
|
||||
bool32 needTMs = FALSE;
|
||||
u16 moveId = MOVE_NONE;
|
||||
bool32 shouldUseMove;
|
||||
u8 level;
|
||||
|
||||
id = APPRENTICE_SPECIES_ID(monId);
|
||||
species = gApprentices[PLAYER_APPRENTICE.id].species[id];
|
||||
learnset = gLevelUpLearnsets[species];
|
||||
j = 0;
|
||||
|
||||
// Despite being open level, level up moves are only read up to level 60
|
||||
if (PLAYER_APPRENTICE.lvlMode == APPRENTICE_LVL_MODE_50)
|
||||
level = 50;
|
||||
else // == APPRENTICE_LVL_MODE_OPEN
|
||||
level = 60;
|
||||
|
||||
for (j = 0; learnset[j] != LEVEL_UP_END; j++)
|
||||
{
|
||||
if ((learnset[j] & LEVEL_UP_MOVE_LV) > (level << 9))
|
||||
break;
|
||||
}
|
||||
|
||||
numLearnsetMoves = j;
|
||||
i = 0;
|
||||
|
||||
// i < 5 here is arbitrary, i isnt used and is only incremented when the selected move isnt in sValidApprenticeMoves
|
||||
// This while loop contains 3 potential infinite loops, though none of them would occur in the base game
|
||||
while (i < 5)
|
||||
{
|
||||
if (Random() % 2 == 0 || needTMs == TRUE)
|
||||
{
|
||||
// Get TM move
|
||||
// NOTE: Below is an infinite loop if a species that only learns TMs for moves
|
||||
// that are also in its level up learnset is assigned to an Apprentice
|
||||
do
|
||||
{
|
||||
// NOTE: Below is an infinite loop if a species which cannot learn TMs is assigned to an Apprentice
|
||||
do
|
||||
{
|
||||
id = Random() % (NUM_TECHNICAL_MACHINES + NUM_HIDDEN_MACHINES);
|
||||
shouldUseMove = CanSpeciesLearnTMHM(species, id);
|
||||
}
|
||||
while (!shouldUseMove);
|
||||
|
||||
moveId = ItemIdToBattleMoveId(ITEM_TM01 + id);
|
||||
shouldUseMove = TRUE;
|
||||
|
||||
if (numLearnsetMoves <= MAX_MON_MOVES)
|
||||
j = 0;
|
||||
else
|
||||
j = numLearnsetMoves - MAX_MON_MOVES;
|
||||
|
||||
for (; j < numLearnsetMoves; j++)
|
||||
{
|
||||
// Keep looking for TMs until one not in the level up learnset is found
|
||||
if ((learnset[j] & LEVEL_UP_MOVE_ID) == moveId)
|
||||
{
|
||||
shouldUseMove = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (shouldUseMove != TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numLearnsetMoves <= MAX_MON_MOVES)
|
||||
{
|
||||
needTMs = TRUE;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get level up move
|
||||
// NOTE: Below is an infinite loop if a mon whose last 4 moves contain
|
||||
// all the moves in the rest of its learnset is assigned to an Apprentice
|
||||
do
|
||||
{
|
||||
// Get a random move excluding the 4 it would know at max level
|
||||
u8 learnsetId = Random() % (numLearnsetMoves - MAX_MON_MOVES);
|
||||
moveId = learnset[learnsetId] & LEVEL_UP_MOVE_ID;
|
||||
shouldUseMove = TRUE;
|
||||
|
||||
for (j = numLearnsetMoves - MAX_MON_MOVES; j < numLearnsetMoves; j++)
|
||||
{
|
||||
// Keep looking for moves until one not in the last 4 is found
|
||||
if ((learnset[j] & LEVEL_UP_MOVE_ID) == moveId)
|
||||
{
|
||||
shouldUseMove = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (shouldUseMove != TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
if (TrySetMove(monId, moveId))
|
||||
{
|
||||
if (sValidApprenticeMoves[moveId])
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
gApprenticePartyMovesData->moveCounter++;
|
||||
return moveId;
|
||||
}
|
||||
|
||||
static bool8 TrySetMove(u8 monId, u16 moveId)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < NUM_WHICH_MOVE_QUESTIONS; i++)
|
||||
{
|
||||
if (gApprenticePartyMovesData->moves[monId][i] == moveId)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gApprenticePartyMovesData->moves[monId][gApprenticePartyMovesData->moveCounter] = moveId;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void GetLatestLearnedMoves(u16 species, u16 *moves)
|
||||
{
|
||||
u8 i, j;
|
||||
u8 level, numLearnsetMoves;
|
||||
const u16 *learnset;
|
||||
|
||||
if (PLAYER_APPRENTICE.lvlMode == APPRENTICE_LVL_MODE_50)
|
||||
level = 50;
|
||||
else // == APPRENTICE_LVL_MODE_OPEN
|
||||
level = 60;
|
||||
|
||||
learnset = gLevelUpLearnsets[species];
|
||||
for (i = 0; learnset[i] != LEVEL_UP_END; i++)
|
||||
{
|
||||
if ((learnset[i] & LEVEL_UP_MOVE_LV) > (level << 9))
|
||||
break;
|
||||
}
|
||||
|
||||
numLearnsetMoves = i;
|
||||
if (numLearnsetMoves > MAX_MON_MOVES)
|
||||
numLearnsetMoves = MAX_MON_MOVES;
|
||||
|
||||
for (j = 0; j < numLearnsetMoves; j++)
|
||||
moves[j] = learnset[(i - 1) - j] & LEVEL_UP_MOVE_ID;
|
||||
}
|
||||
|
||||
// Get the level up move or previously suggested move to be the first move choice
|
||||
// Compare to GetRandomAlternateMove, which gets the move that will be the second choice
|
||||
static u16 GetDefaultMove(u8 monId, u8 speciesArrayId, u8 moveSlot)
|
||||
{
|
||||
u16 moves[MAX_MON_MOVES];
|
||||
u8 i, numQuestions;
|
||||
|
||||
if (PLAYER_APPRENTICE.questionsAnswered < NUM_WHICH_MON_QUESTIONS)
|
||||
return MOVE_NONE;
|
||||
|
||||
numQuestions = 0;
|
||||
for (i = 0; i < APPRENTICE_MAX_QUESTIONS && PLAYER_APPRENTICE.questions[i].questionId != QUESTION_ID_WIN_SPEECH; i++)
|
||||
numQuestions++;
|
||||
|
||||
GetLatestLearnedMoves(gApprentices[PLAYER_APPRENTICE.id].species[speciesArrayId], moves);
|
||||
for (i = 0; i < numQuestions && i < CURRENT_QUESTION_NUM; i++)
|
||||
{
|
||||
if (PLAYER_APPRENTICE.questions[i].questionId == QUESTION_ID_WHICH_MOVE
|
||||
&& PLAYER_APPRENTICE.questions[i].monId == monId
|
||||
&& PLAYER_APPRENTICE.questions[i].suggestedChange)
|
||||
{
|
||||
moves[PLAYER_APPRENTICE.questions[i].moveSlot] = PLAYER_APPRENTICE.questions[i].data;
|
||||
}
|
||||
}
|
||||
|
||||
return moves[moveSlot];
|
||||
}
|
||||
|
||||
static void SaveApprenticeParty(u8 numQuestions)
|
||||
{
|
||||
struct ApprenticeMon *apprenticeMons[MULTI_PARTY_SIZE];
|
||||
u8 i, j;
|
||||
u32 speciesTableId;
|
||||
|
||||
for (i = 0; i < MULTI_PARTY_SIZE; i++)
|
||||
{
|
||||
gSaveBlock2Ptr->apprentices[0].party[i].species = SPECIES_NONE;
|
||||
gSaveBlock2Ptr->apprentices[0].party[i].item = ITEM_NONE;
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
gSaveBlock2Ptr->apprentices[0].party[i].moves[j] = MOVE_NONE;
|
||||
}
|
||||
|
||||
// Save party order
|
||||
j = PLAYER_APPRENTICE.leadMonId;
|
||||
for (i = 0; i < MULTI_PARTY_SIZE; i++)
|
||||
{
|
||||
apprenticeMons[j] = &gSaveBlock2Ptr->apprentices[0].party[i];
|
||||
j = (j + 1) % (MULTI_PARTY_SIZE);
|
||||
}
|
||||
|
||||
// Save party species
|
||||
for (i = 0; i < MULTI_PARTY_SIZE; i++)
|
||||
{
|
||||
speciesTableId = APPRENTICE_SPECIES_ID(i);
|
||||
apprenticeMons[i]->species = gApprentices[PLAYER_APPRENTICE.id].species[speciesTableId];
|
||||
GetLatestLearnedMoves(apprenticeMons[i]->species, apprenticeMons[i]->moves);
|
||||
}
|
||||
|
||||
// Update party based on response to held item / move choice questions
|
||||
for (i = 0; i < numQuestions; i++)
|
||||
{
|
||||
u8 questionId = PLAYER_APPRENTICE.questions[i].questionId;
|
||||
u8 monId = PLAYER_APPRENTICE.questions[i].monId;
|
||||
if (questionId == QUESTION_ID_WHAT_ITEM)
|
||||
{
|
||||
if (PLAYER_APPRENTICE.questions[i].suggestedChange)
|
||||
apprenticeMons[monId]->item = PLAYER_APPRENTICE.questions[i].data;
|
||||
}
|
||||
else if (questionId == QUESTION_ID_WHICH_MOVE)
|
||||
{
|
||||
if (PLAYER_APPRENTICE.questions[i].suggestedChange)
|
||||
{
|
||||
u32 moveSlot = PLAYER_APPRENTICE.questions[i].moveSlot;
|
||||
apprenticeMons[monId]->moves[moveSlot] = PLAYER_APPRENTICE.questions[i].data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CreateApprenticeMenu(u8 menu)
|
||||
{
|
||||
u8 i;
|
||||
u8 windowId;
|
||||
const u8 *strings[3];
|
||||
u8 count = 2;
|
||||
u8 width;
|
||||
u8 left;
|
||||
u8 top;
|
||||
s32 pixelWidth;
|
||||
|
||||
switch (menu)
|
||||
{
|
||||
case APPRENTICE_ASK_WHICH_LEVEL:
|
||||
left = 18;
|
||||
top = 8;
|
||||
strings[0] = gText_Lv50;
|
||||
strings[1] = gText_OpenLevel;
|
||||
break;
|
||||
case APPRENTICE_ASK_3SPECIES:
|
||||
count = MULTI_PARTY_SIZE;
|
||||
left = 18;
|
||||
top = 6;
|
||||
for (i = 0; i < MULTI_PARTY_SIZE; i++)
|
||||
{
|
||||
u16 species;
|
||||
u32 speciesTableId;
|
||||
|
||||
speciesTableId = APPRENTICE_SPECIES_ID(i);
|
||||
species = gApprentices[PLAYER_APPRENTICE.id].species[speciesTableId];
|
||||
strings[i] = gSpeciesNames[species];
|
||||
}
|
||||
break;
|
||||
case APPRENTICE_ASK_2SPECIES:
|
||||
left = 18;
|
||||
top = 8;
|
||||
if (PLAYER_APPRENTICE.questionsAnswered >= NUM_WHICH_MON_QUESTIONS)
|
||||
return;
|
||||
strings[1] = gSpeciesNames[gApprenticeQuestionData->altSpeciesId];
|
||||
strings[0] = gSpeciesNames[gApprenticeQuestionData->speciesId];
|
||||
break;
|
||||
case APPRENTICE_ASK_MOVES:
|
||||
left = 17;
|
||||
top = 8;
|
||||
strings[0] = gMoveNames[gApprenticeQuestionData->moveId1];
|
||||
strings[1] = gMoveNames[gApprenticeQuestionData->moveId2];
|
||||
break;
|
||||
case APPRENTICE_ASK_GIVE:
|
||||
left = 18;
|
||||
top = 8;
|
||||
strings[0] = gText_Give;
|
||||
strings[1] = gText_NoNeed;
|
||||
break;
|
||||
case APPRENTICE_ASK_YES_NO:
|
||||
left = 20;
|
||||
top = 8;
|
||||
strings[0] = gText_Yes;
|
||||
strings[1] = gText_No;
|
||||
break;
|
||||
default:
|
||||
left = 0;
|
||||
top = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
pixelWidth = 0;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
s32 width = GetStringWidth(FONT_NORMAL, strings[i], 0);
|
||||
if (width > pixelWidth)
|
||||
pixelWidth = width;
|
||||
}
|
||||
|
||||
width = ConvertPixelWidthToTileWidth(pixelWidth);
|
||||
left = ScriptMenu_AdjustLeftCoordFromWidth(left, width);
|
||||
windowId = CreateAndShowWindow(left, top, width, count * 2);
|
||||
SetStandardWindowBorderStyle(windowId, 0);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
AddTextPrinterParameterized(windowId, FONT_NORMAL, strings[i], 8, (i * 16) + 1, TEXT_SKIP_DRAW, NULL);
|
||||
|
||||
InitMenuInUpperLeftCornerNormal(windowId, count, 0);
|
||||
CreateChooseAnswerTask(TRUE, count, windowId);
|
||||
}
|
||||
|
||||
#define tNoBButton data[4]
|
||||
#define tWrapAround data[5]
|
||||
#define tWindowId data[6]
|
||||
|
||||
static void Task_ChooseAnswer(u8 taskId)
|
||||
{
|
||||
s8 input;
|
||||
s16 *data = gTasks[taskId].data;
|
||||
|
||||
if (!tWrapAround)
|
||||
input = Menu_ProcessInputNoWrap();
|
||||
else
|
||||
input = Menu_ProcessInput();
|
||||
|
||||
switch (input)
|
||||
{
|
||||
case MENU_NOTHING_CHOSEN:
|
||||
return;
|
||||
case MENU_B_PRESSED:
|
||||
if (tNoBButton)
|
||||
return;
|
||||
|
||||
PlaySE(SE_SELECT);
|
||||
gSpecialVar_Result = 0x7F;
|
||||
break;
|
||||
default:
|
||||
gSpecialVar_Result = input;
|
||||
break;
|
||||
}
|
||||
|
||||
RemoveAndHideWindow(tWindowId);
|
||||
DestroyTask(taskId);
|
||||
EnableBothScriptContexts();
|
||||
}
|
||||
|
||||
static u8 CreateAndShowWindow(u8 left, u8 top, u8 width, u8 height)
|
||||
{
|
||||
u8 windowId;
|
||||
struct WindowTemplate winTemplate = CreateWindowTemplate(0, left + 1, top + 1, width, height, 15, 100);
|
||||
|
||||
windowId = AddWindow(&winTemplate);
|
||||
PutWindowTilemap(windowId);
|
||||
CopyWindowToVram(windowId, COPYWIN_FULL);
|
||||
return windowId;
|
||||
}
|
||||
|
||||
static void RemoveAndHideWindow(u8 windowId)
|
||||
{
|
||||
ClearStdWindowAndFrameToTransparent(windowId, TRUE);
|
||||
RemoveWindow(windowId);
|
||||
}
|
||||
|
||||
static void CreateChooseAnswerTask(bool8 noBButton, u8 answers, u8 windowId)
|
||||
{
|
||||
u8 taskId = CreateTask(Task_ChooseAnswer, 80);
|
||||
gTasks[taskId].tNoBButton = noBButton;
|
||||
|
||||
if (answers > 3)
|
||||
gTasks[taskId].tWrapAround = TRUE;
|
||||
else
|
||||
gTasks[taskId].tWrapAround = FALSE;
|
||||
|
||||
gTasks[taskId].tWindowId = windowId;
|
||||
}
|
||||
|
||||
#undef tNoBButton
|
||||
#undef tWrapAround
|
||||
#undef tWindowId
|
||||
|
||||
void CallApprenticeFunction(void)
|
||||
{
|
||||
sApprenticeFunctions[gSpecialVar_0x8004]();
|
||||
}
|
||||
|
||||
static void Script_ResetPlayerApprentice(void)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
SetApprenticeId();
|
||||
PLAYER_APPRENTICE.lvlMode = 0;
|
||||
PLAYER_APPRENTICE.questionsAnswered = 0;
|
||||
PLAYER_APPRENTICE.leadMonId = 0;
|
||||
PLAYER_APPRENTICE.party = 0;
|
||||
|
||||
for (i = 0; i < MULTI_PARTY_SIZE; i++)
|
||||
PLAYER_APPRENTICE.speciesIds[i] = 0;
|
||||
|
||||
for (i = 0; i < APPRENTICE_MAX_QUESTIONS; i++)
|
||||
{
|
||||
PLAYER_APPRENTICE.questions[i].questionId = 0;
|
||||
PLAYER_APPRENTICE.questions[i].monId = 0;
|
||||
PLAYER_APPRENTICE.questions[i].moveSlot = 0;
|
||||
PLAYER_APPRENTICE.questions[i].suggestedChange = 0;
|
||||
PLAYER_APPRENTICE.questions[i].data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void Script_GivenApprenticeLvlMode(void)
|
||||
{
|
||||
if (!GivenApprenticeLvlMode())
|
||||
gSpecialVar_Result = FALSE;
|
||||
else
|
||||
gSpecialVar_Result = TRUE;
|
||||
}
|
||||
|
||||
// VAR_0x8005 is 1 + the selection value from the multichoice APPRENTICE_ASK_WHICH_LEVEL
|
||||
// i.e. APPRENTICE_LVL_MODE_50 or APPRENTICE_LVL_MODE_OPEN
|
||||
static void Script_SetApprenticeLvlMode(void)
|
||||
{
|
||||
SetPlayersApprenticeLvlMode(gSpecialVar_0x8005);
|
||||
}
|
||||
|
||||
// Never called, APPRENTICE_FUNC_SET_ID is unused
|
||||
static void Script_SetApprenticeId(void)
|
||||
{
|
||||
SetApprenticeId();
|
||||
}
|
||||
|
||||
static void Script_SetRandomQuestionData(void)
|
||||
{
|
||||
SetRandomQuestionData();
|
||||
}
|
||||
|
||||
static void IncrementQuestionsAnswered(void)
|
||||
{
|
||||
PLAYER_APPRENTICE.questionsAnswered++;
|
||||
}
|
||||
|
||||
// The first 3 questions answered after meeting the Apprentice are always selecting party mons
|
||||
// after which this is never called
|
||||
static void GetNumApprenticePartyMonsAssigned(void)
|
||||
{
|
||||
gSpecialVar_Result = PLAYER_APPRENTICE.questionsAnswered;
|
||||
}
|
||||
|
||||
// Never called, APPRENTICE_FUNC_IS_FINAL_QUESTION is unused
|
||||
static void IsFinalQuestion(void)
|
||||
{
|
||||
s32 questionNum = CURRENT_QUESTION_NUM;
|
||||
|
||||
if (questionNum < 0)
|
||||
{
|
||||
// Not finished asking initial questions
|
||||
gSpecialVar_Result = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (questionNum > APPRENTICE_MAX_QUESTIONS - 1)
|
||||
gSpecialVar_Result = TRUE;
|
||||
|
||||
if (PLAYER_APPRENTICE.questions[questionNum].questionId == QUESTION_ID_WIN_SPEECH)
|
||||
gSpecialVar_Result = TRUE;
|
||||
else
|
||||
gSpecialVar_Result = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void Script_CreateApprenticeMenu(void)
|
||||
{
|
||||
CreateApprenticeMenu(gSpecialVar_0x8005);
|
||||
}
|
||||
|
||||
static void Task_WaitForPrintingMessage(u8 taskId)
|
||||
{
|
||||
if (!RunTextPrintersAndIsPrinter0Active())
|
||||
{
|
||||
DestroyTask(taskId);
|
||||
if (gSpecialVar_0x8005)
|
||||
ExecuteFuncAfterButtonPress(EnableBothScriptContexts);
|
||||
else
|
||||
EnableBothScriptContexts();
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintApprenticeMessage(void)
|
||||
{
|
||||
const u8 *string;
|
||||
|
||||
if (gSpecialVar_0x8006 == APPRENTICE_MSG_WHICH_MON)
|
||||
{
|
||||
string = sApprenticeWhichMonTexts[PLAYER_APPRENTICE.id][0];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_THANKS_MON)
|
||||
{
|
||||
string = sApprenticeWhichMonTexts[PLAYER_APPRENTICE.id][1];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_WHICH_MOVE)
|
||||
{
|
||||
string = sApprenticeWhichMoveTexts[PLAYER_APPRENTICE.id][0];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_THANKS_MOVE)
|
||||
{
|
||||
string = sApprenticeWhichMoveTexts[PLAYER_APPRENTICE.id][1];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_WHICH_MON_FIRST)
|
||||
{
|
||||
string = sApprenticeWhichMonFirstTexts[PLAYER_APPRENTICE.id][0];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_THANKS_MON_FIRST)
|
||||
{
|
||||
string = sApprenticeWhichMonFirstTexts[PLAYER_APPRENTICE.id][1];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_WHAT_HELD_ITEM)
|
||||
{
|
||||
string = sApprenticeHeldItemTexts[PLAYER_APPRENTICE.id][0];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_PICK_WIN_SPEECH)
|
||||
{
|
||||
string = sApprenticePickWinSpeechTexts[PLAYER_APPRENTICE.id][0];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_THANKS_HELD_ITEM)
|
||||
{
|
||||
string = sApprenticeHeldItemTexts[PLAYER_APPRENTICE.id][3];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_HOLD_NOTHING)
|
||||
{
|
||||
string = sApprenticeHeldItemTexts[PLAYER_APPRENTICE.id][1];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_ITEM_ALREADY_SUGGESTED)
|
||||
{
|
||||
string = sApprenticeHeldItemTexts[PLAYER_APPRENTICE.id][4];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_THANKS_NO_HELD_ITEM)
|
||||
{
|
||||
string = sApprenticeHeldItemTexts[PLAYER_APPRENTICE.id][2];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_THANKS_WIN_SPEECH)
|
||||
{
|
||||
string = sApprenticePickWinSpeechTexts[PLAYER_APPRENTICE.id][1];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_PLEASE_TEACH)
|
||||
{
|
||||
string = sApprenticeFirstMeetingTexts[PLAYER_APPRENTICE.id][0];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_REJECT)
|
||||
{
|
||||
string = sApprenticeFirstMeetingTexts[PLAYER_APPRENTICE.id][1];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_WHICH_LVL_MODE)
|
||||
{
|
||||
string = sApprenticeFirstMeetingTexts[PLAYER_APPRENTICE.id][2];
|
||||
}
|
||||
else if (gSpecialVar_0x8006 == APPRENTICE_MSG_THANKS_LVL_MODE)
|
||||
{
|
||||
string = sApprenticeFirstMeetingTexts[PLAYER_APPRENTICE.id][3];
|
||||
}
|
||||
else
|
||||
{
|
||||
EnableBothScriptContexts();
|
||||
return;
|
||||
}
|
||||
|
||||
StringExpandPlaceholders(gStringVar4, string);
|
||||
AddTextPrinterForMessage(TRUE);
|
||||
CreateTask(Task_WaitForPrintingMessage, 1);
|
||||
}
|
||||
|
||||
static void Script_PrintApprenticeMessage(void)
|
||||
{
|
||||
ScriptContext2_Enable();
|
||||
FreezeObjectEvents();
|
||||
PlayerFreeze();
|
||||
StopPlayerAvatar();
|
||||
DrawDialogueFrame(0, 1);
|
||||
PrintApprenticeMessage();
|
||||
}
|
||||
|
||||
static void ApprenticeGetQuestion(void)
|
||||
{
|
||||
if (PLAYER_APPRENTICE.questionsAnswered < NUM_WHICH_MON_QUESTIONS)
|
||||
{
|
||||
gSpecialVar_Result = APPRENTICE_QUESTION_WHICH_MON;
|
||||
}
|
||||
else if (PLAYER_APPRENTICE.questionsAnswered > (APPRENTICE_MAX_QUESTIONS + NUM_WHICH_MON_QUESTIONS - 1))
|
||||
{
|
||||
gSpecialVar_Result = APPRENTICE_QUESTION_WIN_SPEECH;
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 id = CURRENT_QUESTION_NUM;
|
||||
switch (PLAYER_APPRENTICE.questions[id].questionId)
|
||||
{
|
||||
case QUESTION_ID_WHAT_ITEM:
|
||||
gSpecialVar_Result = APPRENTICE_QUESTION_WHAT_ITEM;
|
||||
break;
|
||||
case QUESTION_ID_WHICH_MOVE:
|
||||
gSpecialVar_Result = APPRENTICE_QUESTION_WHICH_MOVE;
|
||||
break;
|
||||
case QUESTION_ID_WHICH_FIRST:
|
||||
gSpecialVar_Result = APPRENTICE_QUESTION_WHICH_FIRST;
|
||||
break;
|
||||
default:
|
||||
//case QUESTION_ID_WIN_SPEECH:
|
||||
gSpecialVar_Result = APPRENTICE_QUESTION_WIN_SPEECH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gSpecialVar_0x8005 is 0 or 1 for the mon selection (0 is already on the team)
|
||||
// gSpecialVar_0x8006 is 0-2 for the number of party mons selected so far
|
||||
static void SetApprenticePartyMon(void)
|
||||
{
|
||||
if (gSpecialVar_0x8005)
|
||||
{
|
||||
u8 partySlot = gSpecialVar_0x8006;
|
||||
PLAYER_APPRENTICE.party |= 1 << partySlot;
|
||||
}
|
||||
}
|
||||
|
||||
// gSpecialVar_0x8005 is 0 or 1 for the move selection
|
||||
// Selection 0 is implicitly the default move assigned
|
||||
static void SetApprenticeMonMove(void)
|
||||
{
|
||||
if (PLAYER_APPRENTICE.questionsAnswered >= NUM_WHICH_MON_QUESTIONS)
|
||||
{
|
||||
u8 id = CURRENT_QUESTION_NUM;
|
||||
if (gSpecialVar_0x8005)
|
||||
PLAYER_APPRENTICE.questions[id].suggestedChange = TRUE;
|
||||
else
|
||||
PLAYER_APPRENTICE.questions[id].suggestedChange = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void InitQuestionData(void)
|
||||
{
|
||||
u8 i;
|
||||
u8 count = 0;
|
||||
u8 id1, id2;
|
||||
|
||||
for (i = 0; i < APPRENTICE_MAX_QUESTIONS && (PLAYER_APPRENTICE.questions[i].questionId != QUESTION_ID_WIN_SPEECH); count++, i++)
|
||||
;
|
||||
|
||||
gApprenticeQuestionData = AllocZeroed(sizeof(*gApprenticeQuestionData));
|
||||
if (gSpecialVar_0x8005 == APPRENTICE_QUESTION_WHICH_MON)
|
||||
{
|
||||
if (PLAYER_APPRENTICE.questionsAnswered < NUM_WHICH_MON_QUESTIONS)
|
||||
{
|
||||
// For the first MULTI_PARTY_SIZE (3) questions, a mon is asked to be selected for the Apprentice's party
|
||||
id1 = PLAYER_APPRENTICE.speciesIds[PLAYER_APPRENTICE.questionsAnswered] >> 4;
|
||||
gApprenticeQuestionData->altSpeciesId = gApprentices[PLAYER_APPRENTICE.id].species[id1];
|
||||
|
||||
id2 = PLAYER_APPRENTICE.speciesIds[PLAYER_APPRENTICE.questionsAnswered] & 0xF;
|
||||
gApprenticeQuestionData->speciesId = gApprentices[PLAYER_APPRENTICE.id].species[id2];
|
||||
}
|
||||
}
|
||||
else if (gSpecialVar_0x8005 == APPRENTICE_QUESTION_WHICH_MOVE)
|
||||
{
|
||||
if (PLAYER_APPRENTICE.questionsAnswered >= NUM_WHICH_MON_QUESTIONS
|
||||
&& PLAYER_APPRENTICE.questionsAnswered < count + NUM_WHICH_MON_QUESTIONS
|
||||
&& PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].questionId == QUESTION_ID_WHICH_MOVE)
|
||||
{
|
||||
// count re-used as monId
|
||||
count = PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].monId;
|
||||
APPRENTICE_SPECIES_ID_NO_COND(id1, count);
|
||||
gApprenticeQuestionData->speciesId = gApprentices[PLAYER_APPRENTICE.id].species[id1];
|
||||
gApprenticeQuestionData->moveId1 = GetDefaultMove(count, id1, PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].moveSlot);
|
||||
gApprenticeQuestionData->moveId2 = PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].data;
|
||||
}
|
||||
}
|
||||
else if (gSpecialVar_0x8005 == APPRENTICE_QUESTION_WHAT_ITEM)
|
||||
{
|
||||
if (PLAYER_APPRENTICE.questionsAnswered >= NUM_WHICH_MON_QUESTIONS
|
||||
&& PLAYER_APPRENTICE.questionsAnswered < count + NUM_WHICH_MON_QUESTIONS
|
||||
&& PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].questionId == QUESTION_ID_WHAT_ITEM)
|
||||
{
|
||||
// count re-used as monId
|
||||
count = PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].monId;
|
||||
APPRENTICE_SPECIES_ID_NO_COND(id2, count);
|
||||
gApprenticeQuestionData->speciesId = gApprentices[PLAYER_APPRENTICE.id].species[id2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FreeQuestionData(void)
|
||||
{
|
||||
FREE_AND_SET_NULL(gApprenticeQuestionData);
|
||||
}
|
||||
|
||||
static void ApprenticeBufferString(void)
|
||||
{
|
||||
u8 *stringDst;
|
||||
u8 text[16];
|
||||
u32 speciesArrayId;
|
||||
|
||||
switch (gSpecialVar_0x8005)
|
||||
{
|
||||
case 0:
|
||||
stringDst = gStringVar1;
|
||||
break;
|
||||
case 1:
|
||||
stringDst = gStringVar2;
|
||||
break;
|
||||
case 2:
|
||||
stringDst = gStringVar3;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
switch (gSpecialVar_0x8006)
|
||||
{
|
||||
case APPRENTICE_BUFF_SPECIES1:
|
||||
StringCopy(stringDst, gSpeciesNames[gApprenticeQuestionData->speciesId]);
|
||||
break;
|
||||
case APPRENTICE_BUFF_SPECIES2:
|
||||
StringCopy(stringDst, gSpeciesNames[gApprenticeQuestionData->altSpeciesId]);
|
||||
break;
|
||||
case APPRENTICE_BUFF_SPECIES3:
|
||||
StringCopy(stringDst, gSpeciesNames[gApprenticeQuestionData->speciesId]);
|
||||
break;
|
||||
case APPRENTICE_BUFF_MOVE1:
|
||||
StringCopy(stringDst, gMoveNames[gApprenticeQuestionData->moveId1]);
|
||||
break;
|
||||
case APPRENTICE_BUFF_MOVE2:
|
||||
StringCopy(stringDst, gMoveNames[gApprenticeQuestionData->moveId2]);
|
||||
break;
|
||||
case APPRENTICE_BUFF_ITEM:
|
||||
StringCopy(stringDst, ItemId_GetName(PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].data));
|
||||
break;
|
||||
case APPRENTICE_BUFF_NAME:
|
||||
TVShowConvertInternationalString(text, GetApprenticeNameInLanguage(PLAYER_APPRENTICE.id, GAME_LANGUAGE), GAME_LANGUAGE);
|
||||
StringCopy(stringDst, text);
|
||||
break;
|
||||
case APPRENTICE_BUFF_LEVEL:
|
||||
if (PLAYER_APPRENTICE.lvlMode == APPRENTICE_LVL_MODE_50)
|
||||
StringCopy(stringDst, gText_Lv50);
|
||||
else // == APPRENTICE_LVL_MODE_OPEN
|
||||
StringCopy(stringDst, gText_OpenLevel);
|
||||
break;
|
||||
case APPRENTICE_BUFF_WIN_SPEECH:
|
||||
FrontierSpeechToString(gSaveBlock2Ptr->apprentices[0].speechWon);
|
||||
StringCopy(stringDst, gStringVar4);
|
||||
break;
|
||||
case APPRENTICE_BUFF_LEAD_MON_SPECIES:
|
||||
speciesArrayId = APPRENTICE_SPECIES_ID(PLAYER_APPRENTICE.leadMonId);
|
||||
StringCopy(stringDst, gSpeciesNames[gApprentices[PLAYER_APPRENTICE.id].species[speciesArrayId]]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetLeadApprenticeMon(void)
|
||||
{
|
||||
PLAYER_APPRENTICE.leadMonId = gSpecialVar_0x8005;
|
||||
}
|
||||
|
||||
static void Script_ApprenticeOpenBagMenu(void)
|
||||
{
|
||||
ApprenticeOpenBagMenu();
|
||||
}
|
||||
|
||||
static void TrySetApprenticeHeldItem(void)
|
||||
{
|
||||
u8 i, j;
|
||||
u8 count;
|
||||
|
||||
if (PLAYER_APPRENTICE.questionsAnswered < NUM_WHICH_MON_QUESTIONS)
|
||||
return;
|
||||
|
||||
count = 0;
|
||||
for (j = 0; j < APPRENTICE_MAX_QUESTIONS; j++)
|
||||
{
|
||||
if (PLAYER_APPRENTICE.questions[j].questionId == QUESTION_ID_WIN_SPEECH)
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
|
||||
// Make sure the item hasn't already been suggested in previous questions
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (i >= CURRENT_QUESTION_NUM)
|
||||
break;
|
||||
if (PLAYER_APPRENTICE.questions[i].questionId != QUESTION_ID_WHAT_ITEM ||
|
||||
PLAYER_APPRENTICE.questions[i].suggestedChange == 0)
|
||||
continue;
|
||||
if (PLAYER_APPRENTICE.questions[i].data == gSpecialVar_0x8005)
|
||||
{
|
||||
PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].suggestedChange = FALSE;
|
||||
PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].data = gSpecialVar_0x8005;
|
||||
gSpecialVar_Result = FALSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].suggestedChange = TRUE;
|
||||
PLAYER_APPRENTICE.questions[CURRENT_QUESTION_NUM].data = gSpecialVar_0x8005;
|
||||
gSpecialVar_Result = TRUE;
|
||||
}
|
||||
|
||||
static void ShiftSavedApprentices(void)
|
||||
{
|
||||
s32 i;
|
||||
s32 apprenticeNum;
|
||||
s32 apprenticeIdx;
|
||||
|
||||
if (gSaveBlock2Ptr->apprentices[0].playerName[0] == EOS)
|
||||
return;
|
||||
|
||||
for (i = 0; i < APPRENTICE_COUNT - 1; i++)
|
||||
{
|
||||
if (gSaveBlock2Ptr->apprentices[i + 1].playerName[0] == EOS)
|
||||
{
|
||||
gSaveBlock2Ptr->apprentices[i + 1] = gSaveBlock2Ptr->apprentices[0];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
apprenticeNum = 0xFFFF;
|
||||
apprenticeIdx = -1;
|
||||
for (i = 1; i < APPRENTICE_COUNT; i++)
|
||||
{
|
||||
if (GetTrainerId(gSaveBlock2Ptr->apprentices[i].playerId) == GetTrainerId(gSaveBlock2Ptr->playerTrainerId)
|
||||
&& gSaveBlock2Ptr->apprentices[i].number < apprenticeNum)
|
||||
{
|
||||
apprenticeNum = gSaveBlock2Ptr->apprentices[i].number;
|
||||
apprenticeIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (apprenticeIdx > 0)
|
||||
gSaveBlock2Ptr->apprentices[apprenticeIdx] = gSaveBlock2Ptr->apprentices[0];
|
||||
}
|
||||
|
||||
// Apprentice is always saved in the first slot. Pre-existing Apprentices are moved by ShiftSavedApprentices
|
||||
static void SaveApprentice(void)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
gSaveBlock2Ptr->apprentices[0].id = PLAYER_APPRENTICE.id;
|
||||
gSaveBlock2Ptr->apprentices[0].lvlMode = PLAYER_APPRENTICE.lvlMode;
|
||||
|
||||
// Count questions asked until the final (win speech) question was reached
|
||||
for (i = 0; i < APPRENTICE_MAX_QUESTIONS && (PLAYER_APPRENTICE.questions[i].questionId != QUESTION_ID_WIN_SPEECH); i++)
|
||||
;
|
||||
|
||||
gSaveBlock2Ptr->apprentices[0].numQuestions = i;
|
||||
if (gSaveBlock2Ptr->apprentices[0].number < 255)
|
||||
gSaveBlock2Ptr->apprentices[0].number++;
|
||||
|
||||
SaveApprenticeParty(gSaveBlock2Ptr->apprentices[0].numQuestions);
|
||||
for (i = 0; i < TRAINER_ID_LENGTH; i++)
|
||||
gSaveBlock2Ptr->apprentices[0].playerId[i] = gSaveBlock2Ptr->playerTrainerId[i];
|
||||
|
||||
StringCopy(gSaveBlock2Ptr->apprentices[0].playerName, gSaveBlock2Ptr->playerName);
|
||||
gSaveBlock2Ptr->apprentices[0].language = gGameLanguage;
|
||||
CalcApprenticeChecksum(&gSaveBlock2Ptr->apprentices[0]);
|
||||
}
|
||||
|
||||
// Never called, APPRENTICE_FUNC_SET_GFX_SAVED is unused
|
||||
static void SetSavedApprenticeTrainerGfxId(void)
|
||||
{
|
||||
u8 i;
|
||||
u8 objectEventGfxId;
|
||||
u8 class = gApprentices[gSaveBlock2Ptr->apprentices[0].id].facilityClass;
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerMaleFacilityClasses) && gTowerMaleFacilityClasses[i] != class; i++)
|
||||
;
|
||||
if (i != ARRAY_COUNT(gTowerMaleFacilityClasses))
|
||||
{
|
||||
objectEventGfxId = gTowerMaleTrainerGfxIds[i];
|
||||
VarSet(VAR_OBJ_GFX_ID_0, objectEventGfxId);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerFemaleFacilityClasses) && gTowerFemaleFacilityClasses[i] != class; i++)
|
||||
;
|
||||
if (i != ARRAY_COUNT(gTowerFemaleFacilityClasses))
|
||||
{
|
||||
objectEventGfxId = gTowerFemaleTrainerGfxIds[i];
|
||||
VarSet(VAR_OBJ_GFX_ID_0, objectEventGfxId);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetPlayerApprenticeTrainerGfxId(void)
|
||||
{
|
||||
u8 i;
|
||||
u8 objectEventGfxId;
|
||||
u8 class = gApprentices[PLAYER_APPRENTICE.id].facilityClass;
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerMaleFacilityClasses) && gTowerMaleFacilityClasses[i] != class; i++)
|
||||
;
|
||||
if (i != ARRAY_COUNT(gTowerMaleFacilityClasses))
|
||||
{
|
||||
objectEventGfxId = gTowerMaleTrainerGfxIds[i];
|
||||
VarSet(VAR_OBJ_GFX_ID_0, objectEventGfxId);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(gTowerFemaleFacilityClasses) && gTowerFemaleFacilityClasses[i] != class; i++)
|
||||
;
|
||||
if (i != ARRAY_COUNT(gTowerFemaleFacilityClasses))
|
||||
{
|
||||
objectEventGfxId = gTowerFemaleTrainerGfxIds[i];
|
||||
VarSet(VAR_OBJ_GFX_ID_0, objectEventGfxId);
|
||||
}
|
||||
}
|
||||
|
||||
// Both of the below functions may have been dummied / used for debug
|
||||
// In all cases theres a conditional for VAR_0x8004 right after the call to these functions
|
||||
static void GetShouldCheckApprenticeGone(void)
|
||||
{
|
||||
gSpecialVar_0x8004 = TRUE;
|
||||
}
|
||||
|
||||
static void GetShouldApprenticeLeave(void)
|
||||
{
|
||||
gSpecialVar_0x8004 = TRUE;
|
||||
}
|
||||
|
||||
const u8 *GetApprenticeNameInLanguage(u32 apprenticeId, s32 language)
|
||||
{
|
||||
const struct ApprenticeTrainer *apprentice = &gApprentices[apprenticeId];
|
||||
|
||||
switch (language)
|
||||
{
|
||||
case LANGUAGE_JAPANESE:
|
||||
return apprentice->name[0];
|
||||
case LANGUAGE_ENGLISH:
|
||||
return apprentice->name[1];
|
||||
case LANGUAGE_FRENCH:
|
||||
return apprentice->name[2];
|
||||
case LANGUAGE_ITALIAN:
|
||||
return apprentice->name[3];
|
||||
case LANGUAGE_GERMAN:
|
||||
return apprentice->name[4];
|
||||
case LANGUAGE_SPANISH:
|
||||
default:
|
||||
return apprentice->name[5];
|
||||
}
|
||||
}
|
||||
|
||||
// Functionally unused
|
||||
static void Task_SwitchToFollowupFuncAfterButtonPress(u8 taskId)
|
||||
{
|
||||
if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON))
|
||||
SwitchTaskToFollowupFunc(taskId);
|
||||
}
|
||||
|
||||
static void Task_ExecuteFuncAfterButtonPress(u8 taskId)
|
||||
{
|
||||
if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON))
|
||||
{
|
||||
gApprenticeFunc = (void*)(u32)(((u16)gTasks[taskId].data[0] | (gTasks[taskId].data[1] << 16)));
|
||||
gApprenticeFunc();
|
||||
DestroyTask(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
static void ExecuteFuncAfterButtonPress(void (*func)(void))
|
||||
{
|
||||
u8 taskId = CreateTask(Task_ExecuteFuncAfterButtonPress, 1);
|
||||
gTasks[taskId].data[0] = (u32)(func);
|
||||
gTasks[taskId].data[1] = (u32)(func) >> 16;
|
||||
}
|
||||
|
||||
// Unused
|
||||
static void ExecuteFollowupFuncAfterButtonPress(TaskFunc task)
|
||||
{
|
||||
u8 taskId = CreateTask(Task_SwitchToFollowupFuncAfterButtonPress, 1);
|
||||
SetTaskFuncWithFollowupFunc(taskId, Task_SwitchToFollowupFuncAfterButtonPress, task);
|
||||
}
|
Reference in New Issue
Block a user