Document Trainer Fan Club

This commit is contained in:
GriffinR
2019-11-17 17:34:11 -05:00
committed by huderlem
parent c455fcfa59
commit 5c5c1836bb
15 changed files with 476 additions and 396 deletions
+1 -1
View File
@@ -970,7 +970,7 @@ void sub_80B360C(void)
Overworld_ResetMapMusic();
LoadPlayerParty();
SavePlayerBag();
sub_813BF10();
UpdateTrainerFansAfterLinkBattle();
if (gSpecialVar_0x8004 == USING_SINGLE_BATTLE || gSpecialVar_0x8004 == USING_DOUBLE_BATTLE)
{
+2 -2
View File
@@ -356,7 +356,7 @@ static void sub_80F5CE4(u8 taskId)
InterviewAfter();
}
sub_813BADC(2);
TryGainNewFanFromCounter(2);
sub_80DEDA8(gSpecialVar_ContestRank);
sub_80DEDA8(0xFE);
gUnknown_02039F5C = 1;
@@ -411,7 +411,7 @@ static void sub_80F5CE4(u8 taskId)
sub_80DEDA8(0xFE);
gUnknown_02039F5C = 1;
gUnknown_02039F5D = sub_80DEFA8(0xFE, 0);
sub_813BADC(2);
TryGainNewFanFromCounter(2);
gTasks[taskId].func = sub_80F5F74;
}
}
+180 -111
View File
@@ -92,9 +92,9 @@ extern const u16 gEventObjectPalette17[];
extern const u16 gEventObjectPalette33[];
extern const u16 gEventObjectPalette34[];
void UpdateMovedLilycoveFanClubMembers(void);
void sub_813BF60(void);
u16 GetNumMovedLilycoveFanClubMembers(void);
void TryLoseFansFromPlayTime(void);
void SetPlayerGotFirstFans(void);
u16 GetNumFansOfPlayerInTrainerFanClub(void);
static void RecordCyclingRoadResults(u32, u8);
static void LoadLinkPartnerEventObjectSpritePalette(u8 graphicsId, u8 localEventId, u8 paletteNum);
@@ -131,10 +131,10 @@ static void WaitForDeoxysRockMovement(u8 taskId);
static void sub_813B57C(u8 taskId);
static void Task_LoopWingFlapSE(u8 taskId);
static void Task_CloseBattlePikeCurtain(u8 taskId);
static u8 sub_813BF44(void);
static void sub_813BD84(void);
static u16 sub_813BB74(void);
static void sub_813BE30(struct LinkBattleRecords *linkRecords, u8 a, u8 b);
static u8 DidPlayerGetFirstFans(void);
static void SetInitialFansOfPlayer(void);
static u16 PlayerGainRandomTrainerFan(void);
static void BufferFanClubTrainerName_(struct LinkBattleRecords *linkRecords, u8 a, u8 b);
void Special_ShowDiploma(void)
{
@@ -4019,28 +4019,72 @@ bool8 InPokemonCenter(void)
return FALSE;
}
/* Summary of the Lilycove Trainer Fan Club, because it's a little messy
## The Fan Club room itself
There are initially 4 members of the Fan Club (+ an interviewer), none of whom are fans of the player
After becoming the champion there will be 8 members of the Fan Club, 3 of whom are automatically fans of the player
After this point, if a club member is a fan of the player they will sit at the front table and comment on the player
If they are not fans of the player, they will sit at the far table and can make comments about a different trainer (see BufferFanClubTrainerName)
## Gaining/losing fans
After every link battle the player will gain a fan if they won, or lose a fan if they lost
If the player has at least 3 fans, this is the only way to gain fans
If the player has fewer than 3 fans, they may also gain fans by completing certain tasks enough times (see TryGainNewFanFromCounter)
If the player has at least 5 fans, they can lose a fan every 12 real-time hours, or more often if the timer variable is reset (see TryLoseFansFromPlayTime)
## Variables
VAR_FANCLUB_FAN_COUNTER, a bitfield for tracking the fans
Bits 1-7: Counter for when to add new fans
Bit 8: Flag set after receiving the initial 3 fans
Bits 9-16: Flags for each of the 8 club members, set to 1 when theyre a fan of the player and 0 when theyre not
VAR_FANCLUB_LOSE_FAN_TIMER, a timer for when to lose fans
Compared against playTimeHours. When theyre equal, a fan is ready to be lost
For every fan thats lost this way 12 hours are added to the timer
VAR_LILYCOVE_FAN_CLUB_STATE
0: Player is not the champion yet
1: Player is the champion, ready to meet their initial fans
2: Player has met their initial fans
*/
#define FANCLUB_BITFIELD (gSaveBlock1Ptr->vars[VAR_FANCLUB_FAN_COUNTER - VARS_START])
#define FANCLUB_COUNTER 0x007F
#define FANCLUB_FAN_FLAGS 0xFF80
#define GET_TRAINER_FAN_CLUB_FLAG(flag) (FANCLUB_BITFIELD >> (flag) & 1)
#define SET_TRAINER_FAN_CLUB_FLAG(flag) (FANCLUB_BITFIELD |= 1 << (flag))
#define FLIP_TRAINER_FAN_CLUB_FLAG(flag)(FANCLUB_BITFIELD ^= 1 << (flag))
#define GET_TRAINER_FAN_CLUB_COUNTER (FANCLUB_BITFIELD & FANCLUB_COUNTER)
#define SET_TRAINER_FAN_CLUB_COUNTER(count) (FANCLUB_BITFIELD = (FANCLUB_BITFIELD & FANCLUB_FAN_FLAGS) | (count))
#define INCR_TRAINER_FAN_CLUB_COUNTER(count)(FANCLUB_BITFIELD += (count))
#define CLEAR_TRAINER_FAN_CLUB_COUNTER (FANCLUB_BITFIELD &= ~(FANCLUB_COUNTER))
void ResetFanClub(void)
{
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] = 0;
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_2 - VARS_START] = 0;
gSaveBlock1Ptr->vars[VAR_FANCLUB_FAN_COUNTER - VARS_START] = 0;
gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] = 0;
}
void sub_813BA30(void)
void TryLoseFansFromPlayTimeAfterLinkBattle(void)
{
if (sub_813BF44() != 0)
if (DidPlayerGetFirstFans())
{
UpdateMovedLilycoveFanClubMembers();
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_2 - VARS_START] = gSaveBlock2Ptr->playTimeHours;
TryLoseFansFromPlayTime();
gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] = gSaveBlock2Ptr->playTimeHours;
}
}
void UpdateTrainerFanClubGameClear(void)
{
if (!((gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] >> 7) & 1))
if (!GET_TRAINER_FAN_CLUB_FLAG(FANCLUB_GOT_FIRST_FANS))
{
sub_813BF60();
sub_813BD84();
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_2 - VARS_START] = gSaveBlock2Ptr->playTimeHours;
SetPlayerGotFirstFans();
SetInitialFansOfPlayer();
gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] = gSaveBlock2Ptr->playTimeHours;
FlagClear(FLAG_HIDE_FANCLUB_OLD_LADY);
FlagClear(FLAG_HIDE_FANCLUB_BOY);
FlagClear(FLAG_HIDE_FANCLUB_LITTLE_BOY);
@@ -4050,192 +4094,216 @@ void UpdateTrainerFanClubGameClear(void)
}
}
u8 sub_813BADC(u8 a0)
// If the player has < 3 fans, gain a new fan whenever the counter reaches 20+
// Defeating Drake or participating in a Link Contest increments the counter by 2
// Participating at Battle Tower or in a Secret Base battle increments the counter by 1
u8 TryGainNewFanFromCounter(u8 incrementId)
{
static const u8 gUnknown_085B3470[] = { 2, 1, 2, 1 };
static const u8 sCounterIncrements[] = { 2, 1, 2, 1 };
if (VarGet(VAR_LILYCOVE_FAN_CLUB_STATE) == 2)
{
if ((gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] & 0x7F) + gUnknown_085B3470[a0] > 19)
if (GET_TRAINER_FAN_CLUB_COUNTER + sCounterIncrements[incrementId] > 19)
{
if (GetNumMovedLilycoveFanClubMembers() < 3)
if (GetNumFansOfPlayerInTrainerFanClub() < 3)
{
sub_813BB74();
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] &= 0xFF80;
PlayerGainRandomTrainerFan();
CLEAR_TRAINER_FAN_CLUB_COUNTER;
}
else
{
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] = (gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] & 0xFF80) | 0x14;
SET_TRAINER_FAN_CLUB_COUNTER(20);
}
}
else
{
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] += gUnknown_085B3470[a0];
INCR_TRAINER_FAN_CLUB_COUNTER(sCounterIncrements[incrementId]);
}
}
return gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] & 0x7F;
return GET_TRAINER_FAN_CLUB_COUNTER;
}
static u16 sub_813BB74(void)
// Loop through the fan club members, and if theyre not a fan of the player there is a 50% chance for them to become a fan
// Stops when a fan is gained
// If no new fan was gained while looping, the last non-fan in the list becomes a fan
// If all the members are already fans of the player then this redundantly sets the first fan in the list to be a fan
static u16 PlayerGainRandomTrainerFan(void)
{
static const u8 gUnknown_085B3474[NUM_TRAINER_CLUB_MEMBERS] =
static const u8 sFanClubMemberIds[NUM_TRAINER_FAN_CLUB_MEMBERS] =
{
8, 9, 10, 11, 12, 13, 14, 15
FANCLUB_MEMBER1,
FANCLUB_MEMBER2,
FANCLUB_MEMBER3,
FANCLUB_MEMBER4,
FANCLUB_MEMBER5,
FANCLUB_MEMBER6,
FANCLUB_MEMBER7,
FANCLUB_MEMBER8
};
u8 i;
u8 retVal = 0;
u8 idx = 0;
for (i = 0; i < ARRAY_COUNT(gUnknown_085B3474); i++)
for (i = 0; i < ARRAY_COUNT(sFanClubMemberIds); i++)
{
if (!((gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] >> gUnknown_085B3474[i]) & 1))
if (!GET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[i]))
{
retVal = i;
if ((Random() & 1) != 0)
idx = i;
if (Random() & 1)
{
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] |= 1 << gUnknown_085B3474[retVal];
return retVal;
SET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]);
return idx;
}
}
}
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] |= 1 << gUnknown_085B3474[retVal];
return retVal;
SET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]);
return idx;
}
static u16 sub_813BC00(void)
// Loops through the fan club members, and if theyre a fan of the player there is a 50% chance for them to stop being a fan
// Stops if a fan is removed, or if the player has only one fan left
// If no fan was lost while looping, the last current fan in the list will stop being a fan
static u16 PlayerLoseRandomTrainerFan(void)
{
static const u8 gUnknown_085B347C[NUM_TRAINER_CLUB_MEMBERS] =
static const u8 sFanClubMemberIds[NUM_TRAINER_FAN_CLUB_MEMBERS] =
{
8, 13, 14, 11, 10, 12, 15, 9
FANCLUB_MEMBER1,
FANCLUB_MEMBER6,
FANCLUB_MEMBER7,
FANCLUB_MEMBER4,
FANCLUB_MEMBER3,
FANCLUB_MEMBER5,
FANCLUB_MEMBER8,
FANCLUB_MEMBER2
};
u8 i;
u8 retVal = 0;
u8 idx = 0;
if (GetNumMovedLilycoveFanClubMembers() == 1)
if (GetNumFansOfPlayerInTrainerFanClub() == 1)
{
return 0;
}
for (i = 0; i < ARRAY_COUNT(gUnknown_085B347C); i++)
for (i = 0; i < ARRAY_COUNT(sFanClubMemberIds); i++)
{
if (((gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] >> gUnknown_085B347C[i]) & 1) != 0)
if (GET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[i]))
{
retVal = i;
if ((Random() & 1) != 0)
idx = i;
if (Random() & 1)
{
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] ^= 1 << gUnknown_085B347C[retVal];
return retVal;
FLIP_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]);
return idx;
}
}
}
if (((gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] >> gUnknown_085B347C[retVal]) & 1))
if (GET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]))
{
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] ^= 1 << gUnknown_085B347C[retVal];
FLIP_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]);
}
return retVal;
return idx;
}
u16 GetNumMovedLilycoveFanClubMembers(void)
u16 GetNumFansOfPlayerInTrainerFanClub(void)
{
u8 i;
u8 retVal = 0;
u8 numFans = 0;
for (i = 0; i < NUM_TRAINER_CLUB_MEMBERS; i++)
for (i = 0; i < NUM_TRAINER_FAN_CLUB_MEMBERS; i++)
{
if (((gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] >> (i + 8)) & 1) != 0)
{
retVal++;
}
if (GET_TRAINER_FAN_CLUB_FLAG(i + FANCLUB_MEMBER1))
numFans++;
}
return retVal;
return numFans;
}
void UpdateMovedLilycoveFanClubMembers(void)
// If the player has > 5 fans in the Trainer Fan Club, then lose 1 fan for every 12 hours since the last fan loss / timer reset
void TryLoseFansFromPlayTime(void)
{
u8 i = 0;
if (gSaveBlock2Ptr->playTimeHours < 999)
{
while (TRUE)
{
if (GetNumMovedLilycoveFanClubMembers() < 5)
if (GetNumFansOfPlayerInTrainerFanClub() < 5)
{
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_2 - VARS_START] = gSaveBlock2Ptr->playTimeHours;
gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] = gSaveBlock2Ptr->playTimeHours;
break;
}
else if (i == NUM_TRAINER_CLUB_MEMBERS)
else if (i == NUM_TRAINER_FAN_CLUB_MEMBERS)
{
break;
}
else if (gSaveBlock2Ptr->playTimeHours - gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_2 - VARS_START] < 12)
else if (gSaveBlock2Ptr->playTimeHours - gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] < 12)
{
return;
}
sub_813BC00();
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_2 - VARS_START] += 12;
PlayerLoseRandomTrainerFan();
gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] += 12;
i++;
}
}
}
bool8 ShouldMoveLilycoveFanClubMember(void)
bool8 IsFanClubMemberFanOfPlayer(void)
{
return (gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] >> gSpecialVar_0x8004) & 1;
return GET_TRAINER_FAN_CLUB_FLAG(gSpecialVar_0x8004);
}
static void sub_813BD84(void)
static void SetInitialFansOfPlayer(void)
{
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] |= 0x2000;
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] |= 0x100;
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] |= 0x400;
SET_TRAINER_FAN_CLUB_FLAG(FANCLUB_MEMBER6);
SET_TRAINER_FAN_CLUB_FLAG(FANCLUB_MEMBER1);
SET_TRAINER_FAN_CLUB_FLAG(FANCLUB_MEMBER3);
}
void BufferStreakTrainerText(void)
void BufferFanClubTrainerName(void)
{
u8 a = 0;
u8 b = 0;
u8 whichLinkTrainer = 0;
u8 whichNPCTrainer = 0;
switch (gSpecialVar_0x8004)
{
case 8:
case FANCLUB_MEMBER1:
break;
case 9:
case FANCLUB_MEMBER2:
break;
case 10:
a = 0;
b = 3;
case FANCLUB_MEMBER3:
whichLinkTrainer = 0;
whichNPCTrainer = 3;
break;
case 11:
a = 0;
b = 1;
case FANCLUB_MEMBER4:
whichLinkTrainer = 0;
whichNPCTrainer = 1;
break;
case 12:
a = 1;
b = 0;
case FANCLUB_MEMBER5:
whichLinkTrainer = 1;
whichNPCTrainer = 0;
break;
case 13:
a = 0;
b = 4;
case FANCLUB_MEMBER6:
whichLinkTrainer = 0;
whichNPCTrainer = 4;
break;
case 14:
a = 1;
b = 5;
case FANCLUB_MEMBER7:
whichLinkTrainer = 1;
whichNPCTrainer = 5;
break;
case 15:
case FANCLUB_MEMBER8:
break;
}
sub_813BE30(&gSaveBlock1Ptr->linkBattleRecords, a, b);
BufferFanClubTrainerName_(&gSaveBlock1Ptr->linkBattleRecords, whichLinkTrainer, whichNPCTrainer);
}
static void sub_813BE30(struct LinkBattleRecords *linkRecords, u8 a, u8 b)
static void BufferFanClubTrainerName_(struct LinkBattleRecords *linkRecords, u8 whichLinkTrainer, u8 whichNPCTrainer)
{
struct LinkBattleRecord *record = &linkRecords->entries[a];
struct LinkBattleRecord *record = &linkRecords->entries[whichLinkTrainer];
if (record->name[0] == EOS)
{
switch (b)
switch (whichNPCTrainer)
{
case 0:
StringCopy(gStringVar1, gText_Wallace);
@@ -4262,35 +4330,36 @@ static void sub_813BE30(struct LinkBattleRecords *linkRecords, u8 a, u8 b)
}
else
{
StringCopyN(gStringVar1, record->name, 7);
gStringVar1[7] = EOS;
ConvertInternationalString(gStringVar1, linkRecords->languages[a]);
StringCopyN(gStringVar1, record->name, PLAYER_NAME_LENGTH);
gStringVar1[PLAYER_NAME_LENGTH] = EOS;
ConvertInternationalString(gStringVar1, linkRecords->languages[whichLinkTrainer]);
}
}
void sub_813BF10(void)
void UpdateTrainerFansAfterLinkBattle(void)
{
if (VarGet(VAR_LILYCOVE_FAN_CLUB_STATE) == 2)
{
sub_813BA30();
TryLoseFansFromPlayTimeAfterLinkBattle();
if (gBattleOutcome == B_OUTCOME_WON)
sub_813BB74();
PlayerGainRandomTrainerFan();
else
sub_813BC00();
PlayerLoseRandomTrainerFan();
}
}
static bool8 sub_813BF44(void)
static bool8 DidPlayerGetFirstFans(void)
{
return (gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] >> 7) & 1;
return GET_TRAINER_FAN_CLUB_FLAG(FANCLUB_GOT_FIRST_FANS);
}
void sub_813BF60(void)
void SetPlayerGotFirstFans(void)
{
gSaveBlock1Ptr->vars[VAR_FANCLUB_UNKNOWN_1 - VARS_START] |= 0x80;
SET_TRAINER_FAN_CLUB_FLAG(FANCLUB_GOT_FIRST_FANS);
}
u8 sub_813BF7C(void)
// return value is always ignored
u8 Script_TryGainNewFanFromCounter(void)
{
return sub_813BADC(gSpecialVar_0x8004);
return TryGainNewFanFromCounter(gSpecialVar_0x8004);
}
+1 -1
View File
@@ -1117,7 +1117,7 @@ const u8 *GetSecretBaseTrainerLoseText(void)
void PrepSecretBaseBattleFlags(void)
{
sub_813BADC(1);
TryGainNewFanFromCounter(1);
gTrainerBattleOpponent_A = TRAINER_SECRET_BASE;
gBattleTypeFlags = BATTLE_TYPE_TRAINER | BATTLE_TYPE_SECRET_BASE;
}
+5 -8
View File
@@ -2432,7 +2432,7 @@ u8 TV_MonDataIdxToRibbon(u8 monDataIdx)
return 0;
}
void sub_80EE72C(void)
void TrySetUpTrainerFanClubSpecial(void)
{
TVShow *show;
@@ -2450,22 +2450,19 @@ void sub_80EE72C(void)
}
}
bool8 sub_80EE7C0(void)
bool8 ShouldHideFanClubInterviewer(void)
{
sCurTVShowSlot = FindEmptyTVSlotWithinFirstFiveShowsOfArray(gSaveBlock1Ptr->tvShows);
if (sCurTVShowSlot == -1)
{
return TRUE;
}
FindActiveBroadcastByShowType_SetScriptResult(TVSHOW_FAN_CLUB_SPECIAL);
if (gSpecialVar_Result == TRUE)
{
return TRUE;
}
if (gSaveBlock1Ptr->linkBattleRecords.entries[0].name[0] == EOS)
{
return TRUE;
}
return FALSE;
}