diff options
Diffstat (limited to 'src/field_specials.c')
-rw-r--r-- | src/field_specials.c | 291 |
1 files changed, 180 insertions, 111 deletions
diff --git a/src/field_specials.c b/src/field_specials.c index 57e0d087a..830c2246d 100644 --- a/src/field_specials.c +++ b/src/field_specials.c @@ -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) + If the player has only 1 fan left it cannot be lost + + ## 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); } |