mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-16 19:47:35 +01:00
9917f5cc8b
# Conflicts: # Makefile # include/constants/pokemon.h # include/pokemon.h # make_tools.mk # src/battle_ai_script_commands.c # src/battle_controllers.c # src/battle_main.c # src/battle_script_commands.c # src/party_menu.c # src/pokemon.c # src/trade.c # src/trainer_pokemon_sprites.c
4210 lines
133 KiB
C
4210 lines
133 KiB
C
#include "global.h"
|
|
#include "malloc.h"
|
|
#include "battle.h"
|
|
#include "battle_tower.h"
|
|
#include "cable_club.h"
|
|
#include "data.h"
|
|
#include "decoration.h"
|
|
#include "diploma.h"
|
|
#include "event_data.h"
|
|
#include "event_object_movement.h"
|
|
#include "fieldmap.h"
|
|
#include "field_camera.h"
|
|
#include "field_effect.h"
|
|
#include "field_message_box.h"
|
|
#include "field_player_avatar.h"
|
|
#include "field_screen_effect.h"
|
|
#include "field_specials.h"
|
|
#include "field_weather.h"
|
|
#include "graphics.h"
|
|
#include "international_string_util.h"
|
|
#include "item_icon.h"
|
|
#include "link.h"
|
|
#include "list_menu.h"
|
|
#include "main.h"
|
|
#include "mystery_gift.h"
|
|
#include "match_call.h"
|
|
#include "menu.h"
|
|
#include "overworld.h"
|
|
#include "party_menu.h"
|
|
#include "pokeblock.h"
|
|
#include "pokemon.h"
|
|
#include "pokemon_storage_system.h"
|
|
#include "random.h"
|
|
#include "rayquaza_scene.h"
|
|
#include "region_map.h"
|
|
#include "rtc.h"
|
|
#include "script.h"
|
|
#include "script_menu.h"
|
|
#include "sound.h"
|
|
#include "starter_choose.h"
|
|
#include "string_util.h"
|
|
#include "strings.h"
|
|
#include "task.h"
|
|
#include "text.h"
|
|
#include "tv.h"
|
|
#include "wallclock.h"
|
|
#include "window.h"
|
|
#include "constants/battle_frontier.h"
|
|
#include "constants/battle_pyramid.h"
|
|
#include "constants/battle_tower.h"
|
|
#include "constants/decorations.h"
|
|
#include "constants/event_objects.h"
|
|
#include "constants/event_object_movement.h"
|
|
#include "constants/field_effects.h"
|
|
#include "constants/field_specials.h"
|
|
#include "constants/items.h"
|
|
#include "constants/heal_locations.h"
|
|
#include "constants/map_types.h"
|
|
#include "constants/mystery_gift.h"
|
|
#include "constants/script_menu.h"
|
|
#include "constants/slot_machine.h"
|
|
#include "constants/songs.h"
|
|
#include "constants/moves.h"
|
|
#include "constants/party_menu.h"
|
|
#include "constants/battle_frontier.h"
|
|
#include "constants/weather.h"
|
|
#include "constants/metatile_labels.h"
|
|
#include "palette.h"
|
|
#include "battle_util.h"
|
|
|
|
#define TAG_ITEM_ICON 5500
|
|
|
|
#define GFXTAG_MULTICHOICE_SCROLL_ARROWS 2000
|
|
#define PALTAG_MULTICHOICE_SCROLL_ARROWS 100
|
|
|
|
#define ELEVATOR_WINDOW_WIDTH 3
|
|
#define ELEVATOR_WINDOW_HEIGHT 3
|
|
#define ELEVATOR_LIGHT_STAGES 3
|
|
|
|
EWRAM_DATA bool8 gBikeCyclingChallenge = FALSE;
|
|
EWRAM_DATA u8 gBikeCollisions = 0;
|
|
static EWRAM_DATA u32 sBikeCyclingTimer = 0;
|
|
static EWRAM_DATA u8 sSlidingDoorNextFrameCounter = 0;
|
|
static EWRAM_DATA u8 sSlidingDoorFrame = 0;
|
|
static EWRAM_DATA u8 sTutorMoveAndElevatorWindowId = 0;
|
|
static EWRAM_DATA u16 sLilycoveDeptStore_NeverRead = 0;
|
|
static EWRAM_DATA u16 sLilycoveDeptStore_DefaultFloorChoice = 0;
|
|
static EWRAM_DATA struct ListMenuItem *sScrollableMultichoice_ListMenuItem = NULL;
|
|
static EWRAM_DATA u16 sScrollableMultichoice_ScrollOffset = 0;
|
|
static EWRAM_DATA u16 sFrontierExchangeCorner_NeverRead = 0;
|
|
static EWRAM_DATA u8 sScrollableMultichoice_ItemSpriteId = 0;
|
|
static EWRAM_DATA u8 sBattlePointsWindowId = 0;
|
|
static EWRAM_DATA u8 sFrontierExchangeCorner_ItemIconWindowId = 0;
|
|
static EWRAM_DATA u8 sPCBoxToSendMon = 0;
|
|
static EWRAM_DATA u32 sBattleTowerMultiBattleTypeFlags = 0;
|
|
|
|
struct ListMenuTemplate gScrollableMultichoice_ListMenuTemplate;
|
|
|
|
void TryLoseFansFromPlayTime(void);
|
|
void SetPlayerGotFirstFans(void);
|
|
u16 GetNumFansOfPlayerInTrainerFanClub(void);
|
|
|
|
static void RecordCyclingRoadResults(u32, u8);
|
|
static void LoadLinkPartnerObjectEventSpritePalette(u8, u8, u8);
|
|
static void Task_PetalburgGymSlideOpenRoomDoors(u8);
|
|
static void PetalburgGymSetDoorMetatiles(u8, u16);
|
|
static void Task_PCTurnOnEffect(u8);
|
|
static void PCTurnOnEffect(struct Task *);
|
|
static void PCTurnOnEffect_SetMetatile(s16, s8, s8);
|
|
static void PCTurnOffEffect(void);
|
|
static void Task_LotteryCornerComputerEffect(u8);
|
|
static void LotteryCornerComputerEffect(struct Task *);
|
|
static void Task_ShakeCamera(u8);
|
|
static void StopCameraShake(u8);
|
|
static void Task_MoveElevator(u8);
|
|
static void MoveElevatorWindowLights(u16, bool8);
|
|
static void Task_MoveElevatorWindowLights(u8);
|
|
static void Task_ShowScrollableMultichoice(u8);
|
|
static void FillFrontierExchangeCornerWindowAndItemIcon(u16, u16);
|
|
static void ShowBattleFrontierTutorWindow(u8, u16);
|
|
static void InitScrollableMultichoice(void);
|
|
static void ScrollableMultichoice_ProcessInput(u8);
|
|
static void ScrollableMultichoice_UpdateScrollArrows(u8);
|
|
static void ScrollableMultichoice_MoveCursor(s32, bool8, struct ListMenu *);
|
|
static void HideFrontierExchangeCornerItemIcon(u16, u16);
|
|
static void ShowBattleFrontierTutorMoveDescription(u8, u16);
|
|
static void CloseScrollableMultichoice(u8);
|
|
static void ScrollableMultichoice_RemoveScrollArrows(u8);
|
|
static void Task_ScrollableMultichoice_WaitReturnToList(u8);
|
|
static void Task_ScrollableMultichoice_ReturnToList(u8);
|
|
static void ShowFrontierExchangeCornerItemIcon(u16);
|
|
static void Task_DeoxysRockInteraction(u8);
|
|
static void ChangeDeoxysRockLevel(u8);
|
|
static void WaitForDeoxysRockMovement(u8);
|
|
static void Task_LinkRetireStatusWithBattleTowerPartner(u8);
|
|
static void Task_LoopWingFlapSE(u8);
|
|
static void Task_CloseBattlePikeCurtain(u8);
|
|
static u8 DidPlayerGetFirstFans(void);
|
|
static void SetInitialFansOfPlayer(void);
|
|
static u16 PlayerGainRandomTrainerFan(void);
|
|
static void BufferFanClubTrainerName_(struct LinkBattleRecords *, u8, u8);
|
|
|
|
void Special_ShowDiploma(void)
|
|
{
|
|
SetMainCallback2(CB2_ShowDiploma);
|
|
LockPlayerFieldControls();
|
|
}
|
|
|
|
void Special_ViewWallClock(void)
|
|
{
|
|
gMain.savedCallback = CB2_ReturnToField;
|
|
SetMainCallback2(CB2_ViewWallClock);
|
|
LockPlayerFieldControls();
|
|
}
|
|
|
|
void ResetCyclingRoadChallengeData(void)
|
|
{
|
|
gBikeCyclingChallenge = FALSE;
|
|
gBikeCollisions = 0;
|
|
sBikeCyclingTimer = 0;
|
|
}
|
|
|
|
void Special_BeginCyclingRoadChallenge(void)
|
|
{
|
|
gBikeCyclingChallenge = TRUE;
|
|
gBikeCollisions = 0;
|
|
sBikeCyclingTimer = gMain.vblankCounter1;
|
|
}
|
|
|
|
u16 GetPlayerAvatarBike(void)
|
|
{
|
|
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_ACRO_BIKE))
|
|
return 1;
|
|
if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_MACH_BIKE))
|
|
return 2;
|
|
return 0;
|
|
}
|
|
|
|
static void DetermineCyclingRoadResults(u32 numFrames, u8 numBikeCollisions)
|
|
{
|
|
u8 result;
|
|
|
|
if (numBikeCollisions < 100)
|
|
{
|
|
ConvertIntToDecimalStringN(gStringVar1, numBikeCollisions, STR_CONV_MODE_LEFT_ALIGN, 2);
|
|
StringAppend(gStringVar1, gText_SpaceTimes);
|
|
}
|
|
else
|
|
{
|
|
StringCopy(gStringVar1, gText_99TimesPlus);
|
|
}
|
|
|
|
if (numFrames < 3600)
|
|
{
|
|
ConvertIntToDecimalStringN(gStringVar2, numFrames / 60, STR_CONV_MODE_RIGHT_ALIGN, 2);
|
|
gStringVar2[2] = CHAR_DEC_SEPARATOR;
|
|
ConvertIntToDecimalStringN(&gStringVar2[3], ((numFrames % 60) * 100) / 60, STR_CONV_MODE_LEADING_ZEROS, 2);
|
|
StringAppend(gStringVar2, gText_SpaceSeconds);
|
|
}
|
|
else
|
|
{
|
|
StringCopy(gStringVar2, gText_1MinutePlus);
|
|
}
|
|
|
|
result = 0;
|
|
if (numBikeCollisions == 0)
|
|
result = 5;
|
|
else if (numBikeCollisions < 4)
|
|
result = 4;
|
|
else if (numBikeCollisions < 10)
|
|
result = 3;
|
|
else if (numBikeCollisions < 20)
|
|
result = 2;
|
|
else if (numBikeCollisions < 100)
|
|
result = 1;
|
|
|
|
if (numFrames / 60 <= 10)
|
|
result += 5;
|
|
else if (numFrames / 60 <= 15)
|
|
result += 4;
|
|
else if (numFrames / 60 <= 20)
|
|
result += 3;
|
|
else if (numFrames / 60 <= 40)
|
|
result += 2;
|
|
else if (numFrames / 60 < 60)
|
|
result += 1;
|
|
|
|
gSpecialVar_Result = result;
|
|
}
|
|
|
|
void FinishCyclingRoadChallenge(void)
|
|
{
|
|
const u32 numFrames = gMain.vblankCounter1 - sBikeCyclingTimer;
|
|
|
|
DetermineCyclingRoadResults(numFrames, gBikeCollisions);
|
|
RecordCyclingRoadResults(numFrames, gBikeCollisions);
|
|
}
|
|
|
|
static void RecordCyclingRoadResults(u32 numFrames, u8 numBikeCollisions)
|
|
{
|
|
u16 low = VarGet(VAR_CYCLING_ROAD_RECORD_TIME_L);
|
|
u16 high = VarGet(VAR_CYCLING_ROAD_RECORD_TIME_H);
|
|
u32 framesRecord = low + (high << 16);
|
|
|
|
if (framesRecord > numFrames || framesRecord == 0)
|
|
{
|
|
VarSet(VAR_CYCLING_ROAD_RECORD_TIME_L, numFrames);
|
|
VarSet(VAR_CYCLING_ROAD_RECORD_TIME_H, numFrames >> 16);
|
|
VarSet(VAR_CYCLING_ROAD_RECORD_COLLISIONS, numBikeCollisions);
|
|
}
|
|
}
|
|
|
|
u16 GetRecordedCyclingRoadResults(void)
|
|
{
|
|
u16 low = VarGet(VAR_CYCLING_ROAD_RECORD_TIME_L);
|
|
u16 high = VarGet(VAR_CYCLING_ROAD_RECORD_TIME_H);
|
|
u32 framesRecord = low + (high << 16);
|
|
|
|
if (framesRecord == 0)
|
|
return FALSE;
|
|
|
|
DetermineCyclingRoadResults(framesRecord, VarGet(VAR_CYCLING_ROAD_RECORD_COLLISIONS));
|
|
return TRUE;
|
|
}
|
|
|
|
void UpdateCyclingRoadState(void)
|
|
{
|
|
if (gLastUsedWarp.mapNum == MAP_NUM(ROUTE110_SEASIDE_CYCLING_ROAD_SOUTH_ENTRANCE) && gLastUsedWarp.mapGroup == MAP_GROUP(ROUTE110_SEASIDE_CYCLING_ROAD_SOUTH_ENTRANCE))
|
|
return;
|
|
|
|
if (VarGet(VAR_CYCLING_CHALLENGE_STATE) == 2 || VarGet(VAR_CYCLING_CHALLENGE_STATE) == 3)
|
|
{
|
|
VarSet(VAR_CYCLING_CHALLENGE_STATE, 0);
|
|
Overworld_SetSavedMusic(MUS_DUMMY);
|
|
}
|
|
}
|
|
|
|
void SetSSTidalFlag(void)
|
|
{
|
|
FlagSet(FLAG_SYS_CRUISE_MODE);
|
|
*GetVarPointer(VAR_CRUISE_STEP_COUNT) = 0;
|
|
}
|
|
|
|
void ResetSSTidalFlag(void)
|
|
{
|
|
FlagClear(FLAG_SYS_CRUISE_MODE);
|
|
}
|
|
|
|
// Returns TRUE if the Cruise is over
|
|
bool32 CountSSTidalStep(u16 delta)
|
|
{
|
|
if (!FlagGet(FLAG_SYS_CRUISE_MODE) || (*GetVarPointer(VAR_CRUISE_STEP_COUNT) += delta) < SS_TIDAL_MAX_STEPS)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
u8 GetSSTidalLocation(s8 *mapGroup, s8 *mapNum, s16 *x, s16 *y)
|
|
{
|
|
u16 *varCruiseStepCount = GetVarPointer(VAR_CRUISE_STEP_COUNT);
|
|
switch (*GetVarPointer(VAR_SS_TIDAL_STATE))
|
|
{
|
|
case SS_TIDAL_BOARD_SLATEPORT:
|
|
case SS_TIDAL_LAND_SLATEPORT:
|
|
return SS_TIDAL_LOCATION_SLATEPORT;
|
|
case SS_TIDAL_HALFWAY_LILYCOVE:
|
|
case SS_TIDAL_EXIT_CURRENTS_RIGHT:
|
|
return SS_TIDAL_LOCATION_ROUTE131;
|
|
case SS_TIDAL_LAND_LILYCOVE:
|
|
case SS_TIDAL_BOARD_LILYCOVE:
|
|
return SS_TIDAL_LOCATION_LILYCOVE;
|
|
case SS_TIDAL_DEPART_LILYCOVE:
|
|
case SS_TIDAL_EXIT_CURRENTS_LEFT:
|
|
return SS_TIDAL_LOCATION_ROUTE124;
|
|
case SS_TIDAL_DEPART_SLATEPORT:
|
|
if (*varCruiseStepCount < 60)
|
|
{
|
|
*mapNum = MAP_NUM(ROUTE134);
|
|
*x = *varCruiseStepCount + 19;
|
|
}
|
|
else if (*varCruiseStepCount < 140)
|
|
{
|
|
*mapNum = MAP_NUM(ROUTE133);
|
|
*x = *varCruiseStepCount - 60;
|
|
}
|
|
else
|
|
{
|
|
*mapNum = MAP_NUM(ROUTE132);
|
|
*x = *varCruiseStepCount - 140;
|
|
}
|
|
break;
|
|
case SS_TIDAL_HALFWAY_SLATEPORT:
|
|
if (*varCruiseStepCount < 66)
|
|
{
|
|
*mapNum = MAP_NUM(ROUTE132);
|
|
*x = 65 - *varCruiseStepCount;
|
|
}
|
|
else if (*varCruiseStepCount < 146)
|
|
{
|
|
*mapNum = MAP_NUM(ROUTE133);
|
|
*x = 145 - *varCruiseStepCount;
|
|
}
|
|
else
|
|
{
|
|
*mapNum = MAP_NUM(ROUTE134);
|
|
*x = 224 - *varCruiseStepCount;
|
|
}
|
|
break;
|
|
}
|
|
*mapGroup = MAP_GROUP(ROUTE132);
|
|
*y = 20;
|
|
return SS_TIDAL_LOCATION_CURRENTS;
|
|
}
|
|
|
|
bool32 ShouldDoWallyCall(void)
|
|
{
|
|
if (FlagGet(FLAG_ENABLE_FIRST_WALLY_POKENAV_CALL))
|
|
{
|
|
switch (gMapHeader.mapType)
|
|
{
|
|
case MAP_TYPE_TOWN:
|
|
case MAP_TYPE_CITY:
|
|
case MAP_TYPE_ROUTE:
|
|
case MAP_TYPE_OCEAN_ROUTE:
|
|
if (++(*GetVarPointer(VAR_WALLY_CALL_STEP_COUNTER)) < 250)
|
|
return FALSE;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool32 ShouldDoScottFortreeCall(void)
|
|
{
|
|
if (FlagGet(FLAG_SCOTT_CALL_FORTREE_GYM))
|
|
{
|
|
switch (gMapHeader.mapType)
|
|
{
|
|
case MAP_TYPE_TOWN:
|
|
case MAP_TYPE_CITY:
|
|
case MAP_TYPE_ROUTE:
|
|
case MAP_TYPE_OCEAN_ROUTE:
|
|
if (++(*GetVarPointer(VAR_SCOTT_FORTREE_CALL_STEP_COUNTER)) < 10)
|
|
return FALSE;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool32 ShouldDoScottBattleFrontierCall(void)
|
|
{
|
|
if (FlagGet(FLAG_SCOTT_CALL_BATTLE_FRONTIER))
|
|
{
|
|
switch (gMapHeader.mapType)
|
|
{
|
|
case MAP_TYPE_TOWN:
|
|
case MAP_TYPE_CITY:
|
|
case MAP_TYPE_ROUTE:
|
|
case MAP_TYPE_OCEAN_ROUTE:
|
|
if (++(*GetVarPointer(VAR_SCOTT_BF_CALL_STEP_COUNTER)) < 10)
|
|
return FALSE;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool32 ShouldDoRoxanneCall(void)
|
|
{
|
|
if (FlagGet(FLAG_ENABLE_ROXANNE_FIRST_CALL))
|
|
{
|
|
switch (gMapHeader.mapType)
|
|
{
|
|
case MAP_TYPE_TOWN:
|
|
case MAP_TYPE_CITY:
|
|
case MAP_TYPE_ROUTE:
|
|
case MAP_TYPE_OCEAN_ROUTE:
|
|
if (++(*GetVarPointer(VAR_ROXANNE_CALL_STEP_COUNTER)) < 250)
|
|
return FALSE;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool32 ShouldDoRivalRayquazaCall(void)
|
|
{
|
|
if (FlagGet(FLAG_DEFEATED_MAGMA_SPACE_CENTER))
|
|
{
|
|
switch (gMapHeader.mapType)
|
|
{
|
|
case MAP_TYPE_TOWN:
|
|
case MAP_TYPE_CITY:
|
|
case MAP_TYPE_ROUTE:
|
|
case MAP_TYPE_OCEAN_ROUTE:
|
|
if (++(*GetVarPointer(VAR_RIVAL_RAYQUAZA_CALL_STEP_COUNTER)) < 250)
|
|
return FALSE;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
u8 GetLinkPartnerNames(void)
|
|
{
|
|
u8 i;
|
|
u8 j = 0;
|
|
u8 myLinkPlayerNumber = GetMultiplayerId();
|
|
u8 nLinkPlayers = GetLinkPlayerCount();
|
|
for (i = 0; i < nLinkPlayers; i++)
|
|
{
|
|
if (myLinkPlayerNumber != i)
|
|
{
|
|
StringCopy(gTVStringVarPtrs[j], gLinkPlayers[i].name);
|
|
j++;
|
|
}
|
|
}
|
|
return nLinkPlayers;
|
|
}
|
|
|
|
void SpawnLinkPartnerObjectEvent(void)
|
|
{
|
|
u8 j = 0;
|
|
s16 x = 0;
|
|
s16 y = 0;
|
|
u8 movementTypes[] = {
|
|
MOVEMENT_TYPE_FACE_UP,
|
|
MOVEMENT_TYPE_FACE_LEFT,
|
|
MOVEMENT_TYPE_FACE_DOWN,
|
|
MOVEMENT_TYPE_FACE_RIGHT
|
|
};
|
|
s8 coordOffsets[][2] = {
|
|
{ 0, 1},
|
|
{ 1, 0},
|
|
{ 0, -1},
|
|
{-1, 0}
|
|
};
|
|
u8 myLinkPlayerNumber;
|
|
u8 playerFacingDirection;
|
|
u8 linkSpriteId;
|
|
u8 i;
|
|
|
|
myLinkPlayerNumber = GetMultiplayerId();
|
|
playerFacingDirection = GetPlayerFacingDirection();
|
|
switch (playerFacingDirection)
|
|
{
|
|
case DIR_WEST:
|
|
j = 2;
|
|
x = gSaveBlock1Ptr->pos.x - 1;
|
|
y = gSaveBlock1Ptr->pos.y;
|
|
break;
|
|
case DIR_NORTH:
|
|
j = 1;
|
|
x = gSaveBlock1Ptr->pos.x;
|
|
y = gSaveBlock1Ptr->pos.y - 1;
|
|
break;
|
|
case DIR_EAST:
|
|
x = gSaveBlock1Ptr->pos.x + 1;
|
|
y = gSaveBlock1Ptr->pos.y;
|
|
break;
|
|
case DIR_SOUTH:
|
|
j = 3;
|
|
x = gSaveBlock1Ptr->pos.x;
|
|
y = gSaveBlock1Ptr->pos.y + 1;
|
|
}
|
|
for (i = 0; i < gSpecialVar_0x8004; i++)
|
|
{
|
|
if (myLinkPlayerNumber != i)
|
|
{
|
|
switch ((u8)gLinkPlayers[i].version)
|
|
{
|
|
case VERSION_RUBY:
|
|
case VERSION_SAPPHIRE:
|
|
if (gLinkPlayers[i].gender == 0)
|
|
linkSpriteId = OBJ_EVENT_GFX_LINK_RS_BRENDAN;
|
|
else
|
|
linkSpriteId = OBJ_EVENT_GFX_LINK_RS_MAY;
|
|
break;
|
|
case VERSION_EMERALD:
|
|
if (gLinkPlayers[i].gender == 0)
|
|
linkSpriteId = OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL;
|
|
else
|
|
linkSpriteId = OBJ_EVENT_GFX_RIVAL_MAY_NORMAL;
|
|
break;
|
|
default:
|
|
if (gLinkPlayers[i].gender == 0)
|
|
linkSpriteId = OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL;
|
|
else
|
|
linkSpriteId = OBJ_EVENT_GFX_RIVAL_MAY_NORMAL;
|
|
break;
|
|
}
|
|
SpawnSpecialObjectEventParameterized(linkSpriteId, movementTypes[j], 240 - i, coordOffsets[j][0] + x + MAP_OFFSET, coordOffsets[j][1] + y + MAP_OFFSET, 0);
|
|
LoadLinkPartnerObjectEventSpritePalette(linkSpriteId, 240 - i, i);
|
|
j++;
|
|
if (j == MAX_LINK_PLAYERS)
|
|
j = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void LoadLinkPartnerObjectEventSpritePalette(u8 graphicsId, u8 localEventId, u8 paletteNum)
|
|
{
|
|
u8 adjustedPaletteNum;
|
|
// Note: This temp var is necessary; paletteNum += 6 doesn't match.
|
|
adjustedPaletteNum = paletteNum + 6;
|
|
if (graphicsId == OBJ_EVENT_GFX_LINK_RS_BRENDAN ||
|
|
graphicsId == OBJ_EVENT_GFX_LINK_RS_MAY ||
|
|
graphicsId == OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL ||
|
|
graphicsId == OBJ_EVENT_GFX_RIVAL_MAY_NORMAL)
|
|
{
|
|
u8 obj = GetObjectEventIdByLocalIdAndMap(localEventId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
|
|
if (obj != OBJECT_EVENTS_COUNT)
|
|
{
|
|
u8 spriteId = gObjectEvents[obj].spriteId;
|
|
struct Sprite *sprite = &gSprites[spriteId];
|
|
sprite->oam.paletteNum = adjustedPaletteNum;
|
|
|
|
switch (graphicsId)
|
|
{
|
|
case OBJ_EVENT_GFX_LINK_RS_BRENDAN:
|
|
LoadPalette(gObjectEventPal_RubySapphireBrendan, OBJ_PLTT_ID(adjustedPaletteNum), PLTT_SIZE_4BPP);
|
|
break;
|
|
case OBJ_EVENT_GFX_LINK_RS_MAY:
|
|
LoadPalette(gObjectEventPal_RubySapphireMay, OBJ_PLTT_ID(adjustedPaletteNum), PLTT_SIZE_4BPP);
|
|
break;
|
|
case OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL:
|
|
LoadPalette(gObjectEventPal_Brendan, OBJ_PLTT_ID(adjustedPaletteNum), PLTT_SIZE_4BPP);
|
|
break;
|
|
case OBJ_EVENT_GFX_RIVAL_MAY_NORMAL:
|
|
LoadPalette(gObjectEventPal_May, OBJ_PLTT_ID(adjustedPaletteNum), PLTT_SIZE_4BPP);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static const struct UCoords8 sMauvilleGymSwitchCoords[] =
|
|
{
|
|
{ 0 + MAP_OFFSET, 15 + MAP_OFFSET},
|
|
{ 4 + MAP_OFFSET, 12 + MAP_OFFSET},
|
|
{ 3 + MAP_OFFSET, 9 + MAP_OFFSET},
|
|
{ 8 + MAP_OFFSET, 9 + MAP_OFFSET}
|
|
};
|
|
|
|
// Presses the stepped-on switch and raises the rest
|
|
void MauvilleGymPressSwitch(void)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < ARRAY_COUNT(sMauvilleGymSwitchCoords); i++)
|
|
{
|
|
if (i == gSpecialVar_0x8004)
|
|
MapGridSetMetatileIdAt(sMauvilleGymSwitchCoords[i].x, sMauvilleGymSwitchCoords[i].y, METATILE_MauvilleGym_PressedSwitch);
|
|
else
|
|
MapGridSetMetatileIdAt(sMauvilleGymSwitchCoords[i].x, sMauvilleGymSwitchCoords[i].y, METATILE_MauvilleGym_RaisedSwitch);
|
|
}
|
|
}
|
|
|
|
// Sets the gym barriers back to the default state; their alt state is handled by MauvilleCity_Gym_EventScript_SetAltBarriers
|
|
void MauvilleGymSetDefaultBarriers(void)
|
|
{
|
|
int x, y;
|
|
// All switches/barriers are within these coord ranges
|
|
for (y = 5 + MAP_OFFSET; y < 17 + MAP_OFFSET; y++)
|
|
{
|
|
for (x = 0 + MAP_OFFSET; x < 9 + MAP_OFFSET; x++)
|
|
{
|
|
switch (MapGridGetMetatileIdAt(x, y))
|
|
{
|
|
case METATILE_MauvilleGym_GreenBeamH1_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH1_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH2_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH2_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH3_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH3_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH4_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH4_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH1_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH1_On);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH2_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH2_On);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH3_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH3_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH4_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH4_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH1_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH1_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH2_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH2_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH3_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH3_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH4_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH4_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH1_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH1_On);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH2_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH2_On);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH3_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH3_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH4_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH4_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamV1_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_PoleBottom_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamV2_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_FloorTile);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamV1_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_PoleBottom_Off | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamV2_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_FloorTile);
|
|
break;
|
|
case METATILE_MauvilleGym_PoleBottom_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamV1_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_FloorTile:
|
|
if (MapGridGetMetatileIdAt(x, y - 1) == METATILE_MauvilleGym_GreenBeamV1_On)
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamV2_On | MAPGRID_COLLISION_MASK);
|
|
else
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamV2_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_PoleBottom_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamV1_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_PoleTop_Off:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_PoleTop_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_PoleTop_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_PoleTop_Off);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Presses all switches and deactivates all beams.
|
|
void MauvilleGymDeactivatePuzzle(void)
|
|
{
|
|
int i, x, y;
|
|
const struct UCoords8 *switchCoords = sMauvilleGymSwitchCoords;
|
|
for (i = ARRAY_COUNT(sMauvilleGymSwitchCoords) - 1; i >= 0; i--)
|
|
{
|
|
MapGridSetMetatileIdAt(switchCoords->x, switchCoords->y, METATILE_MauvilleGym_PressedSwitch);
|
|
switchCoords++;
|
|
}
|
|
for (y = 5 + MAP_OFFSET; y < 17 + MAP_OFFSET; y++)
|
|
{
|
|
for (x = 0 + MAP_OFFSET; x < 9 + MAP_OFFSET; x++)
|
|
{
|
|
switch (MapGridGetMetatileIdAt(x, y))
|
|
{
|
|
case METATILE_MauvilleGym_GreenBeamH1_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH1_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH2_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH2_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH3_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH3_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamH4_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_GreenBeamH4_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH1_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH1_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH2_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH2_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH3_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH3_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamH4_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_RedBeamH4_Off);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamV1_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_PoleBottom_On | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_RedBeamV1_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_PoleBottom_Off | MAPGRID_COLLISION_MASK);
|
|
break;
|
|
case METATILE_MauvilleGym_GreenBeamV2_On:
|
|
case METATILE_MauvilleGym_RedBeamV2_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_FloorTile);
|
|
break;
|
|
case METATILE_MauvilleGym_PoleTop_On:
|
|
MapGridSetMetatileIdAt(x, y, METATILE_MauvilleGym_PoleTop_Off);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static const bool8 sSlidingDoorNextFrameDelay[] = {0, 1, 1, 1, 1};
|
|
|
|
static const u16 sPetalburgGymSlidingDoorMetatiles[] = {
|
|
METATILE_PetalburgGym_SlidingDoor_Frame0,
|
|
METATILE_PetalburgGym_SlidingDoor_Frame1,
|
|
METATILE_PetalburgGym_SlidingDoor_Frame2,
|
|
METATILE_PetalburgGym_SlidingDoor_Frame3,
|
|
METATILE_PetalburgGym_SlidingDoor_Frame4,
|
|
};
|
|
|
|
void PetalburgGymSlideOpenRoomDoors(void)
|
|
{
|
|
sSlidingDoorNextFrameCounter = 0;
|
|
sSlidingDoorFrame = 0;
|
|
PlaySE(SE_UNLOCK);
|
|
CreateTask(Task_PetalburgGymSlideOpenRoomDoors, 8);
|
|
}
|
|
|
|
static void Task_PetalburgGymSlideOpenRoomDoors(u8 taskId)
|
|
{
|
|
if (sSlidingDoorNextFrameDelay[sSlidingDoorFrame] == sSlidingDoorNextFrameCounter)
|
|
{
|
|
PetalburgGymSetDoorMetatiles(gSpecialVar_0x8004, sPetalburgGymSlidingDoorMetatiles[sSlidingDoorFrame]);
|
|
sSlidingDoorNextFrameCounter = 0;
|
|
if ((++sSlidingDoorFrame) == ARRAY_COUNT(sPetalburgGymSlidingDoorMetatiles))
|
|
{
|
|
DestroyTask(taskId);
|
|
ScriptContext_Enable();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sSlidingDoorNextFrameCounter++;
|
|
}
|
|
}
|
|
|
|
static void PetalburgGymSetDoorMetatiles(u8 roomNumber, u16 metatileId)
|
|
{
|
|
u16 doorCoordsX[4];
|
|
u16 doorCoordsY[4];
|
|
u8 i;
|
|
u8 nDoors = 0;
|
|
switch (roomNumber)
|
|
{
|
|
case 1:
|
|
nDoors = 2;
|
|
doorCoordsX[0] = 1;
|
|
doorCoordsX[1] = 7;
|
|
doorCoordsY[0] = 104;
|
|
doorCoordsY[1] = 104;
|
|
break;
|
|
case 2:
|
|
nDoors = 2;
|
|
doorCoordsX[0] = 1;
|
|
doorCoordsX[1] = 7;
|
|
doorCoordsY[0] = 78;
|
|
doorCoordsY[1] = 78;
|
|
break;
|
|
case 3:
|
|
nDoors = 2;
|
|
doorCoordsX[0] = 1;
|
|
doorCoordsX[1] = 7;
|
|
doorCoordsY[0] = 91;
|
|
doorCoordsY[1] = 91;
|
|
break;
|
|
case 4:
|
|
nDoors = 1;
|
|
doorCoordsX[0] = 7;
|
|
doorCoordsY[0] = 39;
|
|
break;
|
|
case 5:
|
|
nDoors = 2;
|
|
doorCoordsX[0] = 1;
|
|
doorCoordsX[1] = 7;
|
|
doorCoordsY[0] = 52;
|
|
doorCoordsY[1] = 52;
|
|
break;
|
|
case 6:
|
|
nDoors = 1;
|
|
doorCoordsX[0] = 1;
|
|
doorCoordsY[0] = 65;
|
|
break;
|
|
case 7:
|
|
nDoors = 1;
|
|
doorCoordsX[0] = 7;
|
|
doorCoordsY[0] = 13;
|
|
break;
|
|
case 8:
|
|
nDoors = 1;
|
|
doorCoordsX[0] = 1;
|
|
doorCoordsY[0] = 26;
|
|
break;
|
|
}
|
|
for (i = 0; i < nDoors; i++)
|
|
{
|
|
MapGridSetMetatileIdAt(doorCoordsX[i] + MAP_OFFSET, doorCoordsY[i] + MAP_OFFSET, metatileId | MAPGRID_COLLISION_MASK);
|
|
MapGridSetMetatileIdAt(doorCoordsX[i] + MAP_OFFSET, doorCoordsY[i] + MAP_OFFSET + 1, (metatileId + METATILE_ROW_WIDTH) | MAPGRID_COLLISION_MASK);
|
|
}
|
|
DrawWholeMapView();
|
|
}
|
|
|
|
void PetalburgGymUnlockRoomDoors(void)
|
|
{
|
|
PetalburgGymSetDoorMetatiles(gSpecialVar_0x8004, sPetalburgGymSlidingDoorMetatiles[4]);
|
|
}
|
|
|
|
void ShowFieldMessageStringVar4(void)
|
|
{
|
|
ShowFieldMessage(gStringVar4);
|
|
}
|
|
|
|
void StorePlayerCoordsInVars(void)
|
|
{
|
|
gSpecialVar_0x8004 = gSaveBlock1Ptr->pos.x;
|
|
gSpecialVar_0x8005 = gSaveBlock1Ptr->pos.y;
|
|
}
|
|
|
|
u8 GetPlayerTrainerIdOnesDigit(void)
|
|
{
|
|
return (u16)((gSaveBlock2Ptr->playerTrainerId[1] << 8) | gSaveBlock2Ptr->playerTrainerId[0]) % 10;
|
|
}
|
|
|
|
void GetPlayerBigGuyGirlString(void)
|
|
{
|
|
if (gSaveBlock2Ptr->playerGender == MALE)
|
|
StringCopy(gStringVar1, gText_BigGuy);
|
|
else
|
|
StringCopy(gStringVar1, gText_BigGirl);
|
|
}
|
|
|
|
void GetRivalSonDaughterString(void)
|
|
{
|
|
if (gSaveBlock2Ptr->playerGender == MALE)
|
|
StringCopy(gStringVar1, gText_Daughter);
|
|
else
|
|
StringCopy(gStringVar1, gText_Son);
|
|
}
|
|
|
|
u8 GetBattleOutcome(void)
|
|
{
|
|
return gBattleOutcome;
|
|
}
|
|
|
|
void CableCarWarp(void)
|
|
{
|
|
if (gSpecialVar_0x8004 != 0)
|
|
SetWarpDestination(MAP_GROUP(ROUTE112_CABLE_CAR_STATION), MAP_NUM(ROUTE112_CABLE_CAR_STATION), WARP_ID_NONE, 6, 4);
|
|
else
|
|
SetWarpDestination(MAP_GROUP(MT_CHIMNEY_CABLE_CAR_STATION), MAP_NUM(MT_CHIMNEY_CABLE_CAR_STATION), WARP_ID_NONE, 6, 4);
|
|
}
|
|
|
|
void SetHiddenItemFlag(void)
|
|
{
|
|
FlagSet(gSpecialVar_0x8004);
|
|
}
|
|
|
|
u16 GetWeekCount(void)
|
|
{
|
|
u16 weekCount = gLocalTime.days / 7;
|
|
if (weekCount > 9999)
|
|
weekCount = 9999;
|
|
|
|
return weekCount;
|
|
}
|
|
|
|
u8 GetLeadMonFriendshipScore(void)
|
|
{
|
|
return GetMonFriendshipScore(&gPlayerParty[GetLeadMonIndex()]);
|
|
}
|
|
|
|
static void CB2_FieldShowRegionMap(void)
|
|
{
|
|
FieldInitRegionMap(CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
|
}
|
|
|
|
void FieldShowRegionMap(void)
|
|
{
|
|
SetMainCallback2(CB2_FieldShowRegionMap);
|
|
}
|
|
|
|
static bool8 IsPlayerInFrontOfPC(void)
|
|
{
|
|
u16 x, y;
|
|
u16 tileInFront;
|
|
|
|
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
|
|
tileInFront = MapGridGetMetatileIdAt(x, y);
|
|
|
|
return (tileInFront == METATILE_BrendansMaysHouse_BrendanPC_On
|
|
|| tileInFront == METATILE_BrendansMaysHouse_BrendanPC_Off
|
|
|| tileInFront == METATILE_BrendansMaysHouse_MayPC_On
|
|
|| tileInFront == METATILE_BrendansMaysHouse_MayPC_Off
|
|
|| tileInFront == METATILE_Building_PC_On
|
|
|| tileInFront == METATILE_Building_PC_Off);
|
|
}
|
|
|
|
// Task data for Task_PCTurnOnEffect and Task_LotteryCornerComputerEffect
|
|
#define tPaused data[0] // Never set
|
|
#define tTaskId data[1]
|
|
#define tFlickerCount data[2]
|
|
#define tTimer data[3]
|
|
#define tIsScreenOn data[4]
|
|
|
|
// For this special, gSpecialVar_0x8004 is expected to be some PC_LOCATION_* value.
|
|
void DoPCTurnOnEffect(void)
|
|
{
|
|
if (FuncIsActiveTask(Task_PCTurnOnEffect) != TRUE && IsPlayerInFrontOfPC() == TRUE)
|
|
{
|
|
u8 taskId = CreateTask(Task_PCTurnOnEffect, 8);
|
|
gTasks[taskId].tPaused = FALSE;
|
|
gTasks[taskId].tTaskId = taskId;
|
|
gTasks[taskId].tFlickerCount = 0;
|
|
gTasks[taskId].tTimer = 0;
|
|
gTasks[taskId].tIsScreenOn = FALSE;
|
|
}
|
|
}
|
|
|
|
static void Task_PCTurnOnEffect(u8 taskId)
|
|
{
|
|
struct Task *task = &gTasks[taskId];
|
|
if (!task->tPaused)
|
|
PCTurnOnEffect(task);
|
|
}
|
|
|
|
static void PCTurnOnEffect(struct Task *task)
|
|
{
|
|
u8 playerDirection;
|
|
s8 dx = 0;
|
|
s8 dy = 0;
|
|
if (task->tTimer == 6)
|
|
{
|
|
task->tTimer = 0;
|
|
|
|
// Get where the PC should be, depending on where the player is looking.
|
|
playerDirection = GetPlayerFacingDirection();
|
|
switch (playerDirection)
|
|
{
|
|
case DIR_NORTH:
|
|
dx = 0;
|
|
dy = -1;
|
|
break;
|
|
case DIR_WEST:
|
|
dx = -1;
|
|
dy = -1;
|
|
break;
|
|
case DIR_EAST:
|
|
dx = 1;
|
|
dy = -1;
|
|
break;
|
|
}
|
|
|
|
// Update map
|
|
PCTurnOnEffect_SetMetatile(task->tIsScreenOn, dx, dy);
|
|
DrawWholeMapView();
|
|
|
|
// Screen flickers 5 times. Odd number and starting with the
|
|
// screen off means the animation ends with the screen on.
|
|
task->tIsScreenOn ^= 1;
|
|
if (++task->tFlickerCount == 5)
|
|
DestroyTask(task->tTaskId);
|
|
}
|
|
task->tTimer++;
|
|
}
|
|
|
|
static void PCTurnOnEffect_SetMetatile(s16 isScreenOn, s8 dx, s8 dy)
|
|
{
|
|
u16 metatileId = 0;
|
|
if (isScreenOn)
|
|
{
|
|
// Screen is on, set it off
|
|
if (gSpecialVar_0x8004 == PC_LOCATION_OTHER)
|
|
metatileId = METATILE_Building_PC_Off;
|
|
else if (gSpecialVar_0x8004 == PC_LOCATION_BRENDANS_HOUSE)
|
|
metatileId = METATILE_BrendansMaysHouse_BrendanPC_Off;
|
|
else if (gSpecialVar_0x8004 == PC_LOCATION_MAYS_HOUSE)
|
|
metatileId = METATILE_BrendansMaysHouse_MayPC_Off;
|
|
}
|
|
else
|
|
{
|
|
// Screen is off, set it on
|
|
if (gSpecialVar_0x8004 == PC_LOCATION_OTHER)
|
|
metatileId = METATILE_Building_PC_On;
|
|
else if (gSpecialVar_0x8004 == PC_LOCATION_BRENDANS_HOUSE)
|
|
metatileId = METATILE_BrendansMaysHouse_BrendanPC_On;
|
|
else if (gSpecialVar_0x8004 == PC_LOCATION_MAYS_HOUSE)
|
|
metatileId = METATILE_BrendansMaysHouse_MayPC_On;
|
|
}
|
|
MapGridSetMetatileIdAt(gSaveBlock1Ptr->pos.x + dx + MAP_OFFSET, gSaveBlock1Ptr->pos.y + dy + MAP_OFFSET, metatileId | MAPGRID_COLLISION_MASK);
|
|
}
|
|
|
|
// For this special, gSpecialVar_0x8004 is expected to be some PC_LOCATION_* value.
|
|
void DoPCTurnOffEffect(void)
|
|
{
|
|
PCTurnOffEffect();
|
|
}
|
|
|
|
static void PCTurnOffEffect(void)
|
|
{
|
|
s8 dx = 0;
|
|
s8 dy = 0;
|
|
u16 metatileId = 0;
|
|
|
|
// Get where the PC should be, depending on where the player is looking.
|
|
u8 playerDirection = GetPlayerFacingDirection();
|
|
|
|
if (IsPlayerInFrontOfPC() == FALSE)
|
|
return;
|
|
switch (playerDirection)
|
|
{
|
|
case DIR_NORTH:
|
|
dx = 0;
|
|
dy = -1;
|
|
break;
|
|
case DIR_WEST:
|
|
dx = -1;
|
|
dy = -1;
|
|
break;
|
|
case DIR_EAST:
|
|
dx = 1;
|
|
dy = -1;
|
|
break;
|
|
}
|
|
|
|
if (gSpecialVar_0x8004 == PC_LOCATION_OTHER)
|
|
metatileId = METATILE_Building_PC_Off;
|
|
else if (gSpecialVar_0x8004 == PC_LOCATION_BRENDANS_HOUSE)
|
|
metatileId = METATILE_BrendansMaysHouse_BrendanPC_Off;
|
|
else if (gSpecialVar_0x8004 == PC_LOCATION_MAYS_HOUSE)
|
|
metatileId = METATILE_BrendansMaysHouse_MayPC_Off;
|
|
|
|
MapGridSetMetatileIdAt(gSaveBlock1Ptr->pos.x + dx + MAP_OFFSET, gSaveBlock1Ptr->pos.y + dy + MAP_OFFSET, metatileId | MAPGRID_COLLISION_MASK);
|
|
DrawWholeMapView();
|
|
}
|
|
|
|
void DoLotteryCornerComputerEffect(void)
|
|
{
|
|
if (FuncIsActiveTask(Task_LotteryCornerComputerEffect) != TRUE)
|
|
{
|
|
u8 taskId = CreateTask(Task_LotteryCornerComputerEffect, 8);
|
|
gTasks[taskId].tPaused = FALSE;
|
|
gTasks[taskId].tTaskId = taskId;
|
|
gTasks[taskId].tFlickerCount = 0;
|
|
gTasks[taskId].tTimer = 0;
|
|
gTasks[taskId].tIsScreenOn = FALSE;
|
|
}
|
|
}
|
|
|
|
static void Task_LotteryCornerComputerEffect(u8 taskId)
|
|
{
|
|
struct Task *task = &gTasks[taskId];
|
|
if (!task->tPaused)
|
|
LotteryCornerComputerEffect(task);
|
|
}
|
|
|
|
static void LotteryCornerComputerEffect(struct Task *task)
|
|
{
|
|
if (task->tTimer == 6)
|
|
{
|
|
task->tTimer = 0;
|
|
if (task->tIsScreenOn)
|
|
{
|
|
// Screen is on, set it off
|
|
MapGridSetMetatileIdAt(11 + MAP_OFFSET, 1 + MAP_OFFSET, METATILE_Shop_Laptop1_Normal | MAPGRID_COLLISION_MASK);
|
|
MapGridSetMetatileIdAt(11 + MAP_OFFSET, 2 + MAP_OFFSET, METATILE_Shop_Laptop2_Normal | MAPGRID_COLLISION_MASK);
|
|
}
|
|
else
|
|
{
|
|
// Screen is off, set it on
|
|
MapGridSetMetatileIdAt(11 + MAP_OFFSET, 1 + MAP_OFFSET, METATILE_Shop_Laptop1_Flash | MAPGRID_COLLISION_MASK);
|
|
MapGridSetMetatileIdAt(11 + MAP_OFFSET, 2 + MAP_OFFSET, METATILE_Shop_Laptop2_Flash | MAPGRID_COLLISION_MASK);
|
|
}
|
|
DrawWholeMapView();
|
|
|
|
// Screen flickers 5 times. Odd number and starting with the
|
|
// screen off means the animation ends with the screen on.
|
|
task->tIsScreenOn ^= 1;
|
|
if (++task->tFlickerCount == 5)
|
|
DestroyTask(task->tTaskId);
|
|
}
|
|
task->tTimer++;
|
|
}
|
|
|
|
void EndLotteryCornerComputerEffect(void)
|
|
{
|
|
MapGridSetMetatileIdAt(11 + MAP_OFFSET, 1 + MAP_OFFSET, METATILE_Shop_Laptop1_Normal | MAPGRID_COLLISION_MASK);
|
|
MapGridSetMetatileIdAt(11 + MAP_OFFSET, 2 + MAP_OFFSET, METATILE_Shop_Laptop2_Normal | MAPGRID_COLLISION_MASK);
|
|
DrawWholeMapView();
|
|
}
|
|
|
|
#undef tPaused
|
|
#undef tTaskId
|
|
#undef tFlickerCount
|
|
#undef tTimer
|
|
#undef tIsScreenOn
|
|
|
|
void SetTrickHouseNuggetFlag(void)
|
|
{
|
|
u16 *specVar = &gSpecialVar_0x8004;
|
|
u16 flag = FLAG_HIDDEN_ITEM_TRICK_HOUSE_NUGGET;
|
|
*specVar = flag;
|
|
FlagSet(flag);
|
|
}
|
|
|
|
void ResetTrickHouseNuggetFlag(void)
|
|
{
|
|
u16 *specVar = &gSpecialVar_0x8004;
|
|
u16 flag = FLAG_HIDDEN_ITEM_TRICK_HOUSE_NUGGET;
|
|
*specVar = flag;
|
|
FlagClear(flag);
|
|
}
|
|
|
|
bool8 CheckLeadMonCool(void)
|
|
{
|
|
if (GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_COOL) < 200)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 CheckLeadMonBeauty(void)
|
|
{
|
|
if (GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_BEAUTY) < 200)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 CheckLeadMonCute(void)
|
|
{
|
|
if (GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_CUTE) < 200)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 CheckLeadMonSmart(void)
|
|
{
|
|
if (GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_SMART) < 200)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 CheckLeadMonTough(void)
|
|
{
|
|
if (GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_TOUGH) < 200)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void IsGrassTypeInParty(void)
|
|
{
|
|
u8 i;
|
|
u16 species;
|
|
struct Pokemon *pokemon;
|
|
for (i = 0; i < PARTY_SIZE; i++)
|
|
{
|
|
pokemon = &gPlayerParty[i];
|
|
if (GetMonData(pokemon, MON_DATA_SANITY_HAS_SPECIES) && !GetMonData(pokemon, MON_DATA_IS_EGG))
|
|
{
|
|
species = GetMonData(pokemon, MON_DATA_SPECIES);
|
|
if (gSpeciesInfo[species].types[0] == TYPE_GRASS || gSpeciesInfo[species].types[1] == TYPE_GRASS)
|
|
{
|
|
gSpecialVar_Result = TRUE;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
gSpecialVar_Result = FALSE;
|
|
}
|
|
|
|
void SpawnCameraObject(void)
|
|
{
|
|
u8 obj = SpawnSpecialObjectEventParameterized(OBJ_EVENT_GFX_BOY_1,
|
|
MOVEMENT_TYPE_FACE_DOWN,
|
|
OBJ_EVENT_ID_CAMERA,
|
|
gSaveBlock1Ptr->pos.x + MAP_OFFSET,
|
|
gSaveBlock1Ptr->pos.y + MAP_OFFSET,
|
|
3); // elevation
|
|
gObjectEvents[obj].invisible = TRUE;
|
|
CameraObjectSetFollowedSpriteId(gObjectEvents[obj].spriteId);
|
|
}
|
|
|
|
void RemoveCameraObject(void)
|
|
{
|
|
CameraObjectSetFollowedSpriteId(GetPlayerAvatarSpriteId());
|
|
RemoveObjectEventByLocalIdAndMap(OBJ_EVENT_ID_CAMERA, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
|
|
}
|
|
|
|
u8 GetPokeblockNameByMonNature(void)
|
|
{
|
|
return CopyMonFavoritePokeblockName(GetNature(&gPlayerParty[GetLeadMonIndex()]), gStringVar1);
|
|
}
|
|
|
|
void GetSecretBaseNearbyMapName(void)
|
|
{
|
|
GetMapName(gStringVar1, VarGet(VAR_SECRET_BASE_MAP), 0);
|
|
}
|
|
|
|
u16 GetBattleTowerSinglesStreak(void)
|
|
{
|
|
return GetGameStat(GAME_STAT_BATTLE_TOWER_SINGLES_STREAK);
|
|
}
|
|
|
|
void BufferEReaderTrainerName(void)
|
|
{
|
|
GetEreaderTrainerName(gStringVar1);
|
|
}
|
|
|
|
u16 GetSlotMachineId(void)
|
|
{
|
|
static const u8 sSlotMachineRandomSeeds[SLOT_MACHINE_COUNT] = {12, 2, 4, 5, 1, 8, 7, 11, 3, 10, 9, 6};
|
|
static const u8 sSlotMachineIds[SLOT_MACHINE_COUNT] = {
|
|
SLOT_MACHINE_UNLUCKIEST,
|
|
SLOT_MACHINE_UNLUCKIER,
|
|
SLOT_MACHINE_UNLUCKIER,
|
|
SLOT_MACHINE_UNLUCKY,
|
|
SLOT_MACHINE_UNLUCKY,
|
|
SLOT_MACHINE_UNLUCKY,
|
|
SLOT_MACHINE_LUCKY,
|
|
SLOT_MACHINE_LUCKY,
|
|
SLOT_MACHINE_LUCKY,
|
|
SLOT_MACHINE_LUCKIER,
|
|
SLOT_MACHINE_LUCKIER,
|
|
SLOT_MACHINE_LUCKIEST
|
|
};
|
|
static const u8 sSlotMachineServiceDayIds[SLOT_MACHINE_COUNT] = {
|
|
SLOT_MACHINE_LUCKY,
|
|
SLOT_MACHINE_LUCKY,
|
|
SLOT_MACHINE_LUCKY,
|
|
SLOT_MACHINE_LUCKY,
|
|
SLOT_MACHINE_LUCKY,
|
|
SLOT_MACHINE_LUCKY,
|
|
SLOT_MACHINE_LUCKIER,
|
|
SLOT_MACHINE_LUCKIER,
|
|
SLOT_MACHINE_LUCKIER,
|
|
SLOT_MACHINE_LUCKIER,
|
|
SLOT_MACHINE_LUCKIEST,
|
|
SLOT_MACHINE_LUCKIEST
|
|
};
|
|
|
|
u32 rnd = gSaveBlock1Ptr->dewfordTrends[0].trendiness + gSaveBlock1Ptr->dewfordTrends[0].rand + sSlotMachineRandomSeeds[gSpecialVar_0x8004];
|
|
if (IsPokeNewsActive(POKENEWS_GAME_CORNER))
|
|
return sSlotMachineServiceDayIds[rnd % SLOT_MACHINE_COUNT];
|
|
|
|
return sSlotMachineIds[rnd % SLOT_MACHINE_COUNT];
|
|
}
|
|
|
|
bool8 FoundAbandonedShipRoom1Key(void)
|
|
{
|
|
u16 *specVar = &gSpecialVar_0x8004;
|
|
u16 flag = FLAG_HIDDEN_ITEM_ABANDONED_SHIP_RM_1_KEY;
|
|
*specVar = flag;
|
|
if (!FlagGet(flag))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 FoundAbandonedShipRoom2Key(void)
|
|
{
|
|
u16 *specVar = &gSpecialVar_0x8004;
|
|
u16 flag = FLAG_HIDDEN_ITEM_ABANDONED_SHIP_RM_2_KEY;
|
|
*specVar = flag;
|
|
if (!FlagGet(flag))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 FoundAbandonedShipRoom4Key(void)
|
|
{
|
|
u16 *specVar = &gSpecialVar_0x8004;
|
|
u16 flag = FLAG_HIDDEN_ITEM_ABANDONED_SHIP_RM_4_KEY;
|
|
*specVar = flag;
|
|
if (!FlagGet(flag))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 FoundAbandonedShipRoom6Key(void)
|
|
{
|
|
u16 *specVar = &gSpecialVar_0x8004;
|
|
u16 flag = FLAG_HIDDEN_ITEM_ABANDONED_SHIP_RM_6_KEY;
|
|
*specVar = flag;
|
|
if (!FlagGet(flag))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 LeadMonHasEffortRibbon(void)
|
|
{
|
|
return GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_EFFORT_RIBBON, NULL);
|
|
}
|
|
|
|
void GiveLeadMonEffortRibbon(void)
|
|
{
|
|
bool8 ribbonSet;
|
|
struct Pokemon *leadMon;
|
|
IncrementGameStat(GAME_STAT_RECEIVED_RIBBONS);
|
|
FlagSet(FLAG_SYS_RIBBON_GET);
|
|
ribbonSet = TRUE;
|
|
leadMon = &gPlayerParty[GetLeadMonIndex()];
|
|
SetMonData(leadMon, MON_DATA_EFFORT_RIBBON, &ribbonSet);
|
|
if (GetRibbonCount(leadMon) > NUM_CUTIES_RIBBONS)
|
|
TryPutSpotTheCutiesOnAir(leadMon, MON_DATA_EFFORT_RIBBON);
|
|
}
|
|
|
|
bool8 Special_AreLeadMonEVsMaxedOut(void)
|
|
{
|
|
if (GetMonEVCount(&gPlayerParty[GetLeadMonIndex()]) >= MAX_TOTAL_EVS)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
u8 TryUpdateRusturfTunnelState(void)
|
|
{
|
|
if (!FlagGet(FLAG_RUSTURF_TUNNEL_OPENED)
|
|
&& gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(RUSTURF_TUNNEL)
|
|
&& gSaveBlock1Ptr->location.mapNum == MAP_NUM(RUSTURF_TUNNEL))
|
|
{
|
|
if (FlagGet(FLAG_HIDE_RUSTURF_TUNNEL_ROCK_1))
|
|
{
|
|
VarSet(VAR_RUSTURF_TUNNEL_STATE, 4);
|
|
return TRUE;
|
|
}
|
|
else if (FlagGet(FLAG_HIDE_RUSTURF_TUNNEL_ROCK_2))
|
|
{
|
|
VarSet(VAR_RUSTURF_TUNNEL_STATE, 5);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void SetShoalItemFlag(u16 unused)
|
|
{
|
|
FlagSet(FLAG_SYS_SHOAL_ITEM);
|
|
}
|
|
|
|
void LoadWallyZigzagoon(void)
|
|
{
|
|
u16 monData;
|
|
CreateMon(&gPlayerParty[0], SPECIES_ZIGZAGOON, 7, USE_RANDOM_IVS, FALSE, 0, OT_ID_PLAYER_ID, 0);
|
|
monData = TRUE;
|
|
SetMonData(&gPlayerParty[0], MON_DATA_ABILITY_NUM, &monData);
|
|
monData = MOVE_TACKLE;
|
|
SetMonData(&gPlayerParty[0], MON_DATA_MOVE1, &monData);
|
|
monData = MOVE_NONE;
|
|
SetMonData(&gPlayerParty[0], MON_DATA_MOVE2, &monData);
|
|
SetMonData(&gPlayerParty[0], MON_DATA_MOVE3, &monData);
|
|
SetMonData(&gPlayerParty[0], MON_DATA_MOVE4, &monData);
|
|
}
|
|
|
|
bool8 IsStarterInParty(void)
|
|
{
|
|
u8 i;
|
|
u16 starter = GetStarterPokemon(VarGet(VAR_STARTER_MON));
|
|
u8 partyCount = CalculatePlayerPartyCount();
|
|
for (i = 0; i < partyCount; i++)
|
|
{
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG, NULL) == starter)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool8 ScriptCheckFreePokemonStorageSpace(void)
|
|
{
|
|
return CheckFreePokemonStorageSpace();
|
|
}
|
|
|
|
bool8 IsPokerusInParty(void)
|
|
{
|
|
if (!CheckPartyPokerus(gPlayerParty, (1 << PARTY_SIZE) - 1))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Task data for Task_ShakeCamera
|
|
#define tHorizontalPan data[0]
|
|
#define tDelayCounter data[1]
|
|
#define tNumShakes data[2]
|
|
#define tDelay data[3]
|
|
#define tVerticalPan data[4]
|
|
|
|
void ShakeCamera(void)
|
|
{
|
|
u8 taskId = CreateTask(Task_ShakeCamera, 9);
|
|
gTasks[taskId].tHorizontalPan = gSpecialVar_0x8005;
|
|
gTasks[taskId].tDelayCounter = 0;
|
|
gTasks[taskId].tNumShakes = gSpecialVar_0x8006;
|
|
gTasks[taskId].tDelay = gSpecialVar_0x8007;
|
|
gTasks[taskId].tVerticalPan = gSpecialVar_0x8004;
|
|
SetCameraPanningCallback(NULL);
|
|
PlaySE(SE_M_STRENGTH);
|
|
}
|
|
|
|
static void Task_ShakeCamera(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
tDelayCounter++;
|
|
if (tDelayCounter % tDelay == 0)
|
|
{
|
|
tDelayCounter = 0;
|
|
tNumShakes--;
|
|
tHorizontalPan = -tHorizontalPan;
|
|
tVerticalPan = -tVerticalPan;
|
|
SetCameraPanning(tHorizontalPan, tVerticalPan);
|
|
if (tNumShakes == 0)
|
|
{
|
|
StopCameraShake(taskId);
|
|
InstallCameraPanAheadCallback();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void StopCameraShake(u8 taskId)
|
|
{
|
|
DestroyTask(taskId);
|
|
ScriptContext_Enable();
|
|
}
|
|
|
|
#undef tHorizontalPan
|
|
#undef tDelayCounter
|
|
#undef tNumShakes
|
|
#undef tDelay
|
|
#undef tVerticalPan
|
|
|
|
bool8 FoundBlackGlasses(void)
|
|
{
|
|
return FlagGet(FLAG_HIDDEN_ITEM_ROUTE_116_BLACK_GLASSES);
|
|
}
|
|
|
|
void SetRoute119Weather(void)
|
|
{
|
|
if (IsMapTypeOutdoors(GetLastUsedWarpMapType()) != TRUE)
|
|
SetSavedWeather(WEATHER_ROUTE119_CYCLE);
|
|
}
|
|
|
|
void SetRoute123Weather(void)
|
|
{
|
|
if (IsMapTypeOutdoors(GetLastUsedWarpMapType()) != TRUE)
|
|
SetSavedWeather(WEATHER_ROUTE123_CYCLE);
|
|
}
|
|
|
|
u8 GetLeadMonIndex(void)
|
|
{
|
|
u8 i;
|
|
u8 partyCount = CalculatePlayerPartyCount();
|
|
for (i = 0; i < partyCount; i++)
|
|
{
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG, NULL) != SPECIES_EGG
|
|
&& GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG, NULL) != SPECIES_NONE)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
u16 ScriptGetPartyMonSpecies(void)
|
|
{
|
|
return GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPECIES_OR_EGG, NULL);
|
|
}
|
|
|
|
// Removed for Emerald
|
|
void TryInitBattleTowerAwardManObjectEvent(void)
|
|
{
|
|
//TryInitLocalObjectEvent(6);
|
|
}
|
|
|
|
u16 GetDaysUntilPacifidlogTMAvailable(void)
|
|
{
|
|
u16 tmReceivedDay = VarGet(VAR_PACIFIDLOG_TM_RECEIVED_DAY);
|
|
if (gLocalTime.days - tmReceivedDay >= 7)
|
|
return 0;
|
|
else if (gLocalTime.days < 0)
|
|
return 8;
|
|
|
|
return 7 - (gLocalTime.days - tmReceivedDay);
|
|
}
|
|
|
|
u16 SetPacifidlogTMReceivedDay(void)
|
|
{
|
|
VarSet(VAR_PACIFIDLOG_TM_RECEIVED_DAY, gLocalTime.days);
|
|
return gLocalTime.days;
|
|
}
|
|
|
|
bool8 MonOTNameNotPlayer(void)
|
|
{
|
|
if (GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_LANGUAGE) != GAME_LANGUAGE)
|
|
return TRUE;
|
|
|
|
GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_OT_NAME, gStringVar1);
|
|
|
|
if (!StringCompare(gSaveBlock2Ptr->playerName, gStringVar1))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void BufferLottoTicketNumber(void)
|
|
{
|
|
if (gSpecialVar_Result >= 10000)
|
|
{
|
|
ConvertIntToDecimalString(0, gSpecialVar_Result);
|
|
}
|
|
else if (gSpecialVar_Result >= 1000)
|
|
{
|
|
gStringVar1[0] = CHAR_0;
|
|
ConvertIntToDecimalStringN(gStringVar1 + 1, gSpecialVar_Result, STR_CONV_MODE_LEFT_ALIGN, CountDigits(gSpecialVar_Result));
|
|
}
|
|
else if (gSpecialVar_Result >= 100)
|
|
{
|
|
gStringVar1[0] = CHAR_0;
|
|
gStringVar1[1] = CHAR_0;
|
|
ConvertIntToDecimalStringN(gStringVar1 + 2, gSpecialVar_Result, STR_CONV_MODE_LEFT_ALIGN, CountDigits(gSpecialVar_Result));
|
|
}
|
|
else if (gSpecialVar_Result >= 10)
|
|
{
|
|
gStringVar1[0] = CHAR_0;
|
|
gStringVar1[1] = CHAR_0;
|
|
gStringVar1[2] = CHAR_0;
|
|
ConvertIntToDecimalStringN(gStringVar1 + 3, gSpecialVar_Result, STR_CONV_MODE_LEFT_ALIGN, CountDigits(gSpecialVar_Result));
|
|
}
|
|
else
|
|
{
|
|
gStringVar1[0] = CHAR_0;
|
|
gStringVar1[1] = CHAR_0;
|
|
gStringVar1[2] = CHAR_0;
|
|
gStringVar1[3] = CHAR_0;
|
|
ConvertIntToDecimalStringN(gStringVar1 + 4, gSpecialVar_Result, STR_CONV_MODE_LEFT_ALIGN, CountDigits(gSpecialVar_Result));
|
|
}
|
|
}
|
|
|
|
u16 GetMysteryGiftCardStat(void)
|
|
{
|
|
switch (gSpecialVar_Result)
|
|
{
|
|
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: // Never occurs
|
|
return MysteryGift_GetCardStat(CARD_STAT_BATTLES_LOST);
|
|
case GET_CARD_NUM_TRADES: // Never occurs
|
|
return MysteryGift_GetCardStat(CARD_STAT_NUM_TRADES);
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool8 BufferTMHMMoveName(void)
|
|
{
|
|
if (gSpecialVar_0x8004 >= ITEM_TM01 && gSpecialVar_0x8004 <= ITEM_HM08)
|
|
{
|
|
StringCopy(gStringVar2, gMoveNames[ItemIdToBattleMoveId(gSpecialVar_0x8004)]);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
bool8 IsBadEggInParty(void)
|
|
{
|
|
u8 partyCount = CalculatePlayerPartyCount();
|
|
u8 i;
|
|
|
|
for (i = 0; i < partyCount; i++)
|
|
{
|
|
if (GetMonData(&gPlayerParty[i], MON_DATA_SANITY_IS_BAD_EGG) == TRUE)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
bool8 InMultiPartnerRoom(void)
|
|
{
|
|
if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(BATTLE_FRONTIER_BATTLE_TOWER_MULTI_PARTNER_ROOM)
|
|
&& gSaveBlock1Ptr->location.mapNum == MAP_NUM(BATTLE_FRONTIER_BATTLE_TOWER_MULTI_PARTNER_ROOM) &&
|
|
VarGet(VAR_FRONTIER_BATTLE_MODE) == FRONTIER_MODE_MULTIS)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
void OffsetCameraForBattle(void)
|
|
{
|
|
SetCameraPanningCallback(NULL);
|
|
SetCameraPanning(8, 0);
|
|
}
|
|
|
|
static const struct WindowTemplate sWindowTemplate_ElevatorFloor =
|
|
{
|
|
.bg = 0,
|
|
.tilemapLeft = 21,
|
|
.tilemapTop = 1,
|
|
.width = 8,
|
|
.height = 4,
|
|
.paletteNum = 15,
|
|
.baseBlock = 8,
|
|
};
|
|
|
|
static const u8 *const sDeptStoreFloorNames[] =
|
|
{
|
|
[DEPT_STORE_FLOORNUM_B4F] = gText_B4F,
|
|
[DEPT_STORE_FLOORNUM_B3F] = gText_B3F,
|
|
[DEPT_STORE_FLOORNUM_B2F] = gText_B2F,
|
|
[DEPT_STORE_FLOORNUM_B1F] = gText_B1F,
|
|
[DEPT_STORE_FLOORNUM_1F] = gText_1F,
|
|
[DEPT_STORE_FLOORNUM_2F] = gText_2F,
|
|
[DEPT_STORE_FLOORNUM_3F] = gText_3F,
|
|
[DEPT_STORE_FLOORNUM_4F] = gText_4F,
|
|
[DEPT_STORE_FLOORNUM_5F] = gText_5F,
|
|
[DEPT_STORE_FLOORNUM_6F] = gText_6F,
|
|
[DEPT_STORE_FLOORNUM_7F] = gText_7F,
|
|
[DEPT_STORE_FLOORNUM_8F] = gText_8F,
|
|
[DEPT_STORE_FLOORNUM_9F] = gText_9F,
|
|
[DEPT_STORE_FLOORNUM_10F] = gText_10F,
|
|
[DEPT_STORE_FLOORNUM_11F] = gText_11F,
|
|
[DEPT_STORE_FLOORNUM_ROOFTOP] = gText_Rooftop
|
|
};
|
|
|
|
static const u16 sElevatorWindowTiles_Ascending[ELEVATOR_WINDOW_HEIGHT][ELEVATOR_LIGHT_STAGES] =
|
|
{
|
|
{
|
|
METATILE_BattleFrontier_Elevator_Top0,
|
|
METATILE_BattleFrontier_Elevator_Top1,
|
|
METATILE_BattleFrontier_Elevator_Top2
|
|
},
|
|
{
|
|
METATILE_BattleFrontier_Elevator_Mid0,
|
|
METATILE_BattleFrontier_Elevator_Mid1,
|
|
METATILE_BattleFrontier_Elevator_Mid2
|
|
},
|
|
{
|
|
METATILE_BattleFrontier_Elevator_Bottom0,
|
|
METATILE_BattleFrontier_Elevator_Bottom1,
|
|
METATILE_BattleFrontier_Elevator_Bottom2
|
|
},
|
|
};
|
|
|
|
static const u16 sElevatorWindowTiles_Descending[ELEVATOR_WINDOW_HEIGHT][ELEVATOR_LIGHT_STAGES] =
|
|
{
|
|
{
|
|
METATILE_BattleFrontier_Elevator_Top0,
|
|
METATILE_BattleFrontier_Elevator_Top2,
|
|
METATILE_BattleFrontier_Elevator_Top1
|
|
},
|
|
{
|
|
METATILE_BattleFrontier_Elevator_Mid0,
|
|
METATILE_BattleFrontier_Elevator_Mid2,
|
|
METATILE_BattleFrontier_Elevator_Mid1
|
|
},
|
|
{
|
|
METATILE_BattleFrontier_Elevator_Bottom0,
|
|
METATILE_BattleFrontier_Elevator_Bottom2,
|
|
METATILE_BattleFrontier_Elevator_Bottom1
|
|
},
|
|
};
|
|
|
|
void SetDeptStoreFloor(void)
|
|
{
|
|
u8 deptStoreFloor;
|
|
switch (gSaveBlock1Ptr->dynamicWarp.mapNum)
|
|
{
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_1F):
|
|
deptStoreFloor = DEPT_STORE_FLOORNUM_1F;
|
|
break;
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_2F):
|
|
deptStoreFloor = DEPT_STORE_FLOORNUM_2F;
|
|
break;
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_3F):
|
|
deptStoreFloor = DEPT_STORE_FLOORNUM_3F;
|
|
break;
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_4F):
|
|
deptStoreFloor = DEPT_STORE_FLOORNUM_4F;
|
|
break;
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_5F):
|
|
deptStoreFloor = DEPT_STORE_FLOORNUM_5F;
|
|
break;
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_ROOFTOP):
|
|
deptStoreFloor = DEPT_STORE_FLOORNUM_ROOFTOP;
|
|
break;
|
|
default:
|
|
deptStoreFloor = DEPT_STORE_FLOORNUM_1F;
|
|
break;
|
|
}
|
|
VarSet(VAR_DEPT_STORE_FLOOR, deptStoreFloor);
|
|
}
|
|
|
|
u16 GetDeptStoreDefaultFloorChoice(void)
|
|
{
|
|
sLilycoveDeptStore_NeverRead = 0;
|
|
sLilycoveDeptStore_DefaultFloorChoice = 0;
|
|
|
|
if (gSaveBlock1Ptr->dynamicWarp.mapGroup == MAP_GROUP(LILYCOVE_CITY_DEPARTMENT_STORE_1F))
|
|
{
|
|
switch (gSaveBlock1Ptr->dynamicWarp.mapNum)
|
|
{
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_5F):
|
|
sLilycoveDeptStore_NeverRead = 0;
|
|
sLilycoveDeptStore_DefaultFloorChoice = 0;
|
|
break;
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_4F):
|
|
sLilycoveDeptStore_NeverRead = 0;
|
|
sLilycoveDeptStore_DefaultFloorChoice = 1;
|
|
break;
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_3F):
|
|
sLilycoveDeptStore_NeverRead = 0;
|
|
sLilycoveDeptStore_DefaultFloorChoice = 2;
|
|
break;
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_2F):
|
|
sLilycoveDeptStore_NeverRead = 0;
|
|
sLilycoveDeptStore_DefaultFloorChoice = 3;
|
|
break;
|
|
case MAP_NUM(LILYCOVE_CITY_DEPARTMENT_STORE_1F):
|
|
sLilycoveDeptStore_NeverRead = 0;
|
|
sLilycoveDeptStore_DefaultFloorChoice = 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return sLilycoveDeptStore_DefaultFloorChoice;
|
|
}
|
|
|
|
// Task data for Task_MoveElevator
|
|
#define tTimer data[1]
|
|
#define tMoveCounter data[2]
|
|
#define tVerticalPan data[4]
|
|
#define tTotalMoves data[5]
|
|
#define tDescending data[6]
|
|
|
|
// The maximum considered difference between floors.
|
|
// Elevator trips with a larger difference are treated the same
|
|
// (i.e. traveling 9 floors and 200 floors would take the same amount of time).
|
|
#define MAX_ELEVATOR_TRIP 9
|
|
|
|
// gSpecialVar_0x8005 here is expected to be the current floor number, and
|
|
// gSpecialVar_0x8006 is expected to be the destination floor number.
|
|
void MoveElevator(void)
|
|
{
|
|
static const u8 sElevatorTripLength[MAX_ELEVATOR_TRIP] = { 8, 16, 24, 32, 38, 46, 52, 56, 57 };
|
|
|
|
s16 *data = gTasks[CreateTask(Task_MoveElevator, 9)].data;
|
|
u16 floorDelta;
|
|
|
|
tTimer = 0;
|
|
tMoveCounter = 0;
|
|
tVerticalPan = 1;
|
|
|
|
if (gSpecialVar_0x8005 > gSpecialVar_0x8006)
|
|
{
|
|
floorDelta = gSpecialVar_0x8005 - gSpecialVar_0x8006;
|
|
tDescending = TRUE;
|
|
}
|
|
else
|
|
{
|
|
floorDelta = gSpecialVar_0x8006 - gSpecialVar_0x8005;
|
|
tDescending = FALSE;
|
|
}
|
|
|
|
if (floorDelta > MAX_ELEVATOR_TRIP - 1)
|
|
floorDelta = MAX_ELEVATOR_TRIP - 1;
|
|
|
|
tTotalMoves = sElevatorTripLength[floorDelta];
|
|
|
|
SetCameraPanningCallback(NULL);
|
|
MoveElevatorWindowLights(floorDelta, tDescending);
|
|
PlaySE(SE_ELEVATOR);
|
|
}
|
|
|
|
static void Task_MoveElevator(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
tTimer++;
|
|
if (tTimer % 3 == 0)
|
|
{
|
|
tTimer = 0;
|
|
tMoveCounter++;
|
|
tVerticalPan = -tVerticalPan;
|
|
SetCameraPanning(0, tVerticalPan);
|
|
|
|
if (tMoveCounter == tTotalMoves)
|
|
{
|
|
// Arrived at floor
|
|
PlaySE(SE_DING_DONG);
|
|
DestroyTask(taskId);
|
|
ScriptContext_Enable();
|
|
InstallCameraPanAheadCallback();
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef tTimer
|
|
#undef tMoveCounter
|
|
#undef tVerticalPan
|
|
#undef tTotalMoves
|
|
#undef tDescending
|
|
|
|
void ShowDeptStoreElevatorFloorSelect(void)
|
|
{
|
|
int xPos;
|
|
|
|
sTutorMoveAndElevatorWindowId = AddWindow(&sWindowTemplate_ElevatorFloor);
|
|
SetStandardWindowBorderStyle(sTutorMoveAndElevatorWindowId, FALSE);
|
|
|
|
xPos = GetStringCenterAlignXOffset(FONT_NORMAL, gText_ElevatorNowOn, 64);
|
|
AddTextPrinterParameterized(sTutorMoveAndElevatorWindowId, FONT_NORMAL, gText_ElevatorNowOn, xPos, 1, TEXT_SKIP_DRAW, NULL);
|
|
|
|
xPos = GetStringCenterAlignXOffset(FONT_NORMAL, sDeptStoreFloorNames[gSpecialVar_0x8005], 64);
|
|
AddTextPrinterParameterized(sTutorMoveAndElevatorWindowId, FONT_NORMAL, sDeptStoreFloorNames[gSpecialVar_0x8005], xPos, 17, TEXT_SKIP_DRAW, NULL);
|
|
|
|
PutWindowTilemap(sTutorMoveAndElevatorWindowId);
|
|
CopyWindowToVram(sTutorMoveAndElevatorWindowId, COPYWIN_FULL);
|
|
}
|
|
|
|
void CloseDeptStoreElevatorWindow(void)
|
|
{
|
|
ClearStdWindowAndFrameToTransparent(sTutorMoveAndElevatorWindowId, TRUE);
|
|
RemoveWindow(sTutorMoveAndElevatorWindowId);
|
|
}
|
|
|
|
// Task data for Task_MoveElevatorWindowLights
|
|
#define tMoveCounter data[0]
|
|
#define tTimer data[1]
|
|
#define tDescending data[2]
|
|
#define tTotalMoves data[3]
|
|
|
|
static void MoveElevatorWindowLights(u16 floorDelta, bool8 descending)
|
|
{
|
|
static const u8 sElevatorLightCycles[MAX_ELEVATOR_TRIP] = { 3, 6, 9, 12, 15, 18, 21, 24, 27 };
|
|
|
|
if (FuncIsActiveTask(Task_MoveElevatorWindowLights) != TRUE)
|
|
{
|
|
u8 taskId = CreateTask(Task_MoveElevatorWindowLights, 8);
|
|
gTasks[taskId].tMoveCounter = 0;
|
|
gTasks[taskId].tTimer = 0;
|
|
gTasks[taskId].tDescending = descending;
|
|
gTasks[taskId].tTotalMoves = sElevatorLightCycles[floorDelta];
|
|
}
|
|
}
|
|
|
|
static void Task_MoveElevatorWindowLights(u8 taskId)
|
|
{
|
|
u8 x, y;
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
if (tTimer == 6)
|
|
{
|
|
tMoveCounter++;
|
|
|
|
if (!tDescending)
|
|
{
|
|
// Ascending
|
|
for (y = 0; y < ELEVATOR_WINDOW_HEIGHT; y++)
|
|
{
|
|
for (x = 0; x < ELEVATOR_WINDOW_WIDTH; x++)
|
|
MapGridSetMetatileIdAt(x + MAP_OFFSET + 1, y + MAP_OFFSET, sElevatorWindowTiles_Ascending[y][tMoveCounter % ELEVATOR_LIGHT_STAGES] | MAPGRID_COLLISION_MASK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Descending
|
|
for (y = 0; y < ELEVATOR_WINDOW_HEIGHT; y++)
|
|
{
|
|
for (x = 0; x < ELEVATOR_WINDOW_WIDTH; x++)
|
|
MapGridSetMetatileIdAt(x + MAP_OFFSET + 1, y + MAP_OFFSET, sElevatorWindowTiles_Descending[y][tMoveCounter % ELEVATOR_LIGHT_STAGES] | MAPGRID_COLLISION_MASK);
|
|
}
|
|
}
|
|
DrawWholeMapView();
|
|
tTimer = 0;
|
|
if (tMoveCounter == tTotalMoves)
|
|
DestroyTask(taskId);
|
|
}
|
|
tTimer++;
|
|
}
|
|
|
|
#undef tMoveCounter
|
|
#undef tTimer
|
|
#undef tDescending
|
|
#undef tTotalMoves
|
|
|
|
void BufferVarsForIVRater(void)
|
|
{
|
|
u8 i;
|
|
u32 ivStorage[NUM_STATS];
|
|
|
|
ivStorage[STAT_HP] = GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_HP_IV);
|
|
ivStorage[STAT_ATK] = GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_ATK_IV);
|
|
ivStorage[STAT_DEF] = GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_DEF_IV);
|
|
ivStorage[STAT_SPEED] = GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPEED_IV);
|
|
ivStorage[STAT_SPATK] = GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPATK_IV);
|
|
ivStorage[STAT_SPDEF] = GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPDEF_IV);
|
|
|
|
gSpecialVar_0x8005 = 0;
|
|
|
|
for (i = 0; i < NUM_STATS; i++)
|
|
gSpecialVar_0x8005 += ivStorage[i];
|
|
|
|
gSpecialVar_0x8006 = 0;
|
|
gSpecialVar_0x8007 = ivStorage[STAT_HP];
|
|
|
|
for (i = 1; i < NUM_STATS; i++)
|
|
{
|
|
if (ivStorage[gSpecialVar_0x8006] < ivStorage[i])
|
|
{
|
|
gSpecialVar_0x8006 = i;
|
|
gSpecialVar_0x8007 = ivStorage[i];
|
|
}
|
|
else if (ivStorage[gSpecialVar_0x8006] == ivStorage[i])
|
|
{
|
|
u16 randomNumber = Random();
|
|
if (randomNumber & 1)
|
|
{
|
|
gSpecialVar_0x8006 = i;
|
|
gSpecialVar_0x8007 = ivStorage[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool8 UsedPokemonCenterWarp(void)
|
|
{
|
|
static const u16 sPokemonCenters[] =
|
|
{
|
|
MAP_OLDALE_TOWN_POKEMON_CENTER_1F,
|
|
MAP_DEWFORD_TOWN_POKEMON_CENTER_1F,
|
|
MAP_LAVARIDGE_TOWN_POKEMON_CENTER_1F,
|
|
MAP_FALLARBOR_TOWN_POKEMON_CENTER_1F,
|
|
MAP_VERDANTURF_TOWN_POKEMON_CENTER_1F,
|
|
MAP_PACIFIDLOG_TOWN_POKEMON_CENTER_1F,
|
|
MAP_PETALBURG_CITY_POKEMON_CENTER_1F,
|
|
MAP_SLATEPORT_CITY_POKEMON_CENTER_1F,
|
|
MAP_MAUVILLE_CITY_POKEMON_CENTER_1F,
|
|
MAP_RUSTBORO_CITY_POKEMON_CENTER_1F,
|
|
MAP_FORTREE_CITY_POKEMON_CENTER_1F,
|
|
MAP_LILYCOVE_CITY_POKEMON_CENTER_1F,
|
|
MAP_MOSSDEEP_CITY_POKEMON_CENTER_1F,
|
|
MAP_SOOTOPOLIS_CITY_POKEMON_CENTER_1F,
|
|
MAP_EVER_GRANDE_CITY_POKEMON_CENTER_1F,
|
|
MAP_EVER_GRANDE_CITY_POKEMON_LEAGUE_1F,
|
|
MAP_BATTLE_FRONTIER_POKEMON_CENTER_1F,
|
|
MAP_UNION_ROOM,
|
|
MAP_UNDEFINED
|
|
};
|
|
|
|
int i;
|
|
u16 map = (gLastUsedWarp.mapGroup << 8) + gLastUsedWarp.mapNum;
|
|
|
|
for (i = 0; sPokemonCenters[i] != MAP_UNDEFINED; i++)
|
|
{
|
|
if (sPokemonCenters[i] == map)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
bool32 PlayerNotAtTrainerHillEntrance(void)
|
|
{
|
|
if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(TRAINER_HILL_ENTRANCE) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(TRAINER_HILL_ENTRANCE))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void UpdateFrontierManiac(u16 daysSince)
|
|
{
|
|
u16 *var = GetVarPointer(VAR_FRONTIER_MANIAC_FACILITY);
|
|
*var += daysSince;
|
|
*var %= FRONTIER_MANIAC_FACILITY_COUNT;
|
|
}
|
|
|
|
void ShowFrontierManiacMessage(void)
|
|
{
|
|
static const u8 *const sFrontierManiacMessages[][FRONTIER_MANIAC_MESSAGE_COUNT] =
|
|
{
|
|
[FRONTIER_MANIAC_TOWER_SINGLES] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_SalonMaidenIsThere,
|
|
BattleFrontier_Lounge2_Text_SalonMaidenSilverMons,
|
|
BattleFrontier_Lounge2_Text_SalonMaidenGoldMons
|
|
},
|
|
[FRONTIER_MANIAC_TOWER_DOUBLES] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_DoubleBattleAdvice1,
|
|
BattleFrontier_Lounge2_Text_DoubleBattleAdvice2,
|
|
BattleFrontier_Lounge2_Text_DoubleBattleAdvice3
|
|
},
|
|
[FRONTIER_MANIAC_TOWER_MULTIS] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_MultiBattleAdvice,
|
|
BattleFrontier_Lounge2_Text_MultiBattleAdvice,
|
|
BattleFrontier_Lounge2_Text_MultiBattleAdvice
|
|
},
|
|
[FRONTIER_MANIAC_TOWER_LINK] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_LinkMultiBattleAdvice,
|
|
BattleFrontier_Lounge2_Text_LinkMultiBattleAdvice,
|
|
BattleFrontier_Lounge2_Text_LinkMultiBattleAdvice
|
|
},
|
|
[FRONTIER_MANIAC_DOME] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_DomeAceIsThere,
|
|
BattleFrontier_Lounge2_Text_DomeAceSilverMons,
|
|
BattleFrontier_Lounge2_Text_DomeAceGoldMons
|
|
},
|
|
[FRONTIER_MANIAC_FACTORY] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_FactoryHeadIsThere,
|
|
BattleFrontier_Lounge2_Text_FactoryHeadSilverMons,
|
|
BattleFrontier_Lounge2_Text_FactoryHeadGoldMons
|
|
},
|
|
[FRONTIER_MANIAC_PALACE] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_PalaceMavenIsThere,
|
|
BattleFrontier_Lounge2_Text_PalaceMavenSilverMons,
|
|
BattleFrontier_Lounge2_Text_PalaceMavenGoldMons
|
|
},
|
|
[FRONTIER_MANIAC_ARENA] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_ArenaTycoonIsThere,
|
|
BattleFrontier_Lounge2_Text_ArenaTycoonSilverMons,
|
|
BattleFrontier_Lounge2_Text_ArenaTycoonGoldMons
|
|
},
|
|
[FRONTIER_MANIAC_PIKE] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_PikeQueenIsThere,
|
|
BattleFrontier_Lounge2_Text_PikeQueenSilverMons,
|
|
BattleFrontier_Lounge2_Text_PikeQueenGoldMons
|
|
},
|
|
[FRONTIER_MANIAC_PYRAMID] =
|
|
{
|
|
BattleFrontier_Lounge2_Text_PyramidKingIsThere,
|
|
BattleFrontier_Lounge2_Text_PyramidKingSilverMons,
|
|
BattleFrontier_Lounge2_Text_PyramidKingGoldMons
|
|
},
|
|
};
|
|
|
|
static const u8 sFrontierManiacStreakThresholds[][FRONTIER_MANIAC_MESSAGE_COUNT - 1] =
|
|
{
|
|
[FRONTIER_MANIAC_TOWER_SINGLES] = { 21, 56 },
|
|
[FRONTIER_MANIAC_TOWER_DOUBLES] = { 21, 35 },
|
|
[FRONTIER_MANIAC_TOWER_MULTIS] = { 255, 255 },
|
|
[FRONTIER_MANIAC_TOWER_LINK] = { 255, 255 },
|
|
[FRONTIER_MANIAC_DOME] = { 2, 4 },
|
|
[FRONTIER_MANIAC_FACTORY] = { 7, 21 },
|
|
[FRONTIER_MANIAC_PALACE] = { 7, 21 },
|
|
[FRONTIER_MANIAC_ARENA] = { 14, 28 },
|
|
[FRONTIER_MANIAC_PIKE] = { 13, 112 }, //BUG: 112 (0x70) is probably a mistake; the Pike Queen is battled twice well before that
|
|
[FRONTIER_MANIAC_PYRAMID] = { 7, 56 }
|
|
};
|
|
|
|
u8 i;
|
|
u16 winStreak = 0;
|
|
u16 facility = VarGet(VAR_FRONTIER_MANIAC_FACILITY);
|
|
|
|
switch (facility)
|
|
{
|
|
case FRONTIER_MANIAC_TOWER_SINGLES:
|
|
case FRONTIER_MANIAC_TOWER_DOUBLES:
|
|
case FRONTIER_MANIAC_TOWER_MULTIS:
|
|
case FRONTIER_MANIAC_TOWER_LINK:
|
|
if (gSaveBlock2Ptr->frontier.towerWinStreaks[facility][FRONTIER_LVL_50]
|
|
>= gSaveBlock2Ptr->frontier.towerWinStreaks[facility][FRONTIER_LVL_OPEN])
|
|
winStreak = gSaveBlock2Ptr->frontier.towerWinStreaks[facility][FRONTIER_LVL_50];
|
|
else
|
|
winStreak = gSaveBlock2Ptr->frontier.towerWinStreaks[facility][FRONTIER_LVL_OPEN];
|
|
break;
|
|
case FRONTIER_MANIAC_DOME:
|
|
if (gSaveBlock2Ptr->frontier.domeWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_50]
|
|
>= gSaveBlock2Ptr->frontier.domeWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_OPEN])
|
|
winStreak = gSaveBlock2Ptr->frontier.domeWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_50];
|
|
else
|
|
winStreak = gSaveBlock2Ptr->frontier.domeWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_OPEN];
|
|
break;
|
|
case FRONTIER_MANIAC_FACTORY:
|
|
if (gSaveBlock2Ptr->frontier.factoryWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_50]
|
|
>= gSaveBlock2Ptr->frontier.factoryWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_OPEN])
|
|
winStreak = gSaveBlock2Ptr->frontier.factoryWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_50];
|
|
else
|
|
winStreak = gSaveBlock2Ptr->frontier.factoryWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_OPEN];
|
|
break;
|
|
case FRONTIER_MANIAC_PALACE:
|
|
if (gSaveBlock2Ptr->frontier.palaceWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_50]
|
|
>= gSaveBlock2Ptr->frontier.palaceWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_OPEN])
|
|
winStreak = gSaveBlock2Ptr->frontier.palaceWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_50];
|
|
else
|
|
winStreak = gSaveBlock2Ptr->frontier.palaceWinStreaks[FRONTIER_MODE_SINGLES][FRONTIER_LVL_OPEN];
|
|
break;
|
|
case FRONTIER_MANIAC_ARENA:
|
|
if (gSaveBlock2Ptr->frontier.arenaWinStreaks[FRONTIER_LVL_50]
|
|
>= gSaveBlock2Ptr->frontier.arenaWinStreaks[FRONTIER_LVL_OPEN])
|
|
winStreak = gSaveBlock2Ptr->frontier.arenaWinStreaks[FRONTIER_LVL_50];
|
|
else
|
|
winStreak = gSaveBlock2Ptr->frontier.arenaWinStreaks[FRONTIER_LVL_OPEN];
|
|
break;
|
|
case FRONTIER_MANIAC_PIKE:
|
|
if (gSaveBlock2Ptr->frontier.pikeWinStreaks[FRONTIER_LVL_50]
|
|
>= gSaveBlock2Ptr->frontier.pikeWinStreaks[FRONTIER_LVL_OPEN])
|
|
winStreak = gSaveBlock2Ptr->frontier.pikeWinStreaks[FRONTIER_LVL_50];
|
|
else
|
|
winStreak = gSaveBlock2Ptr->frontier.pikeWinStreaks[FRONTIER_LVL_OPEN];
|
|
break;
|
|
case FRONTIER_MANIAC_PYRAMID:
|
|
if (gSaveBlock2Ptr->frontier.pyramidWinStreaks[FRONTIER_LVL_50]
|
|
>= gSaveBlock2Ptr->frontier.pyramidWinStreaks[FRONTIER_LVL_OPEN])
|
|
winStreak = gSaveBlock2Ptr->frontier.pyramidWinStreaks[FRONTIER_LVL_50];
|
|
else
|
|
winStreak = gSaveBlock2Ptr->frontier.pyramidWinStreaks[FRONTIER_LVL_OPEN];
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < FRONTIER_MANIAC_MESSAGE_COUNT - 1 && sFrontierManiacStreakThresholds[facility][i] < winStreak; i++);
|
|
|
|
ShowFieldMessage(sFrontierManiacMessages[facility][i]);
|
|
}
|
|
|
|
// gSpecialVar_0x8005 and 0x8006 here are used by MoveElevator
|
|
void BufferBattleTowerElevatorFloors(void)
|
|
{
|
|
static const u16 sBattleTowerStreakThresholds[] = {
|
|
7, 14, 21, 28, 35, 49, 63, 77, 91, 0
|
|
};
|
|
|
|
u8 i;
|
|
u16 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE);
|
|
u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
|
|
|
|
if (battleMode == FRONTIER_MODE_MULTIS && !FlagGet(FLAG_CHOSEN_MULTI_BATTLE_NPC_PARTNER))
|
|
{
|
|
gSpecialVar_0x8005 = 5;
|
|
gSpecialVar_0x8006 = 4;
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sBattleTowerStreakThresholds) - 1; i++)
|
|
{
|
|
if (sBattleTowerStreakThresholds[i] > gSaveBlock2Ptr->frontier.towerWinStreaks[battleMode][lvlMode])
|
|
{
|
|
gSpecialVar_0x8005 = 4;
|
|
gSpecialVar_0x8006 = i + 5;
|
|
return;
|
|
}
|
|
}
|
|
|
|
gSpecialVar_0x8005 = 4;
|
|
gSpecialVar_0x8006 = 12;
|
|
}
|
|
|
|
// Scrollable Multichoice task data defines
|
|
#define tMaxItemsOnScreen data[0]
|
|
#define tNumItems data[1]
|
|
#define tLeft data[2]
|
|
#define tTop data[3]
|
|
#define tWidth data[4]
|
|
#define tHeight data[5]
|
|
#define tKeepOpenAfterSelect data[6]
|
|
#define tScrollOffset data[7]
|
|
#define tSelectedRow data[8]
|
|
#define tScrollMultiId data[11]
|
|
#define tScrollArrowId data[12]
|
|
#define tWindowId data[13]
|
|
#define tListTaskId data[14]
|
|
#define tTaskId data[15]
|
|
// data[9] and [10] unused
|
|
|
|
void ShowScrollableMultichoice(void)
|
|
{
|
|
u8 taskId = CreateTask(Task_ShowScrollableMultichoice, 8);
|
|
struct Task *task = &gTasks[taskId];
|
|
task->tScrollMultiId = gSpecialVar_0x8004;
|
|
|
|
switch (gSpecialVar_0x8004)
|
|
{
|
|
case SCROLL_MULTI_NONE:
|
|
task->tMaxItemsOnScreen = 1;
|
|
task->tNumItems = 1;
|
|
task->tLeft = 1;
|
|
task->tTop = 1;
|
|
task->tWidth = 1;
|
|
task->tHeight = 1;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_GLASS_WORKSHOP_VENDOR:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN - 1;
|
|
task->tNumItems = 8;
|
|
task->tLeft = 1;
|
|
task->tTop = 1;
|
|
task->tWidth = 9;
|
|
task->tHeight = 10;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_POKEMON_FAN_CLUB_RATER:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 12;
|
|
task->tLeft = 1;
|
|
task->tTop = 1;
|
|
task->tWidth = 7;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_1:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 11;
|
|
task->tLeft = 14;
|
|
task->tTop = 1;
|
|
task->tWidth = 15;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_2:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 6;
|
|
task->tLeft = 14;
|
|
task->tTop = 1;
|
|
task->tWidth = 15;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_VITAMIN_VENDOR:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 7;
|
|
task->tLeft = 14;
|
|
task->tTop = 1;
|
|
task->tWidth = 15;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_HOLD_ITEM_VENDOR:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 10;
|
|
task->tLeft = 14;
|
|
task->tTop = 1;
|
|
task->tWidth = 15;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_BERRY_POWDER_VENDOR:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 12;
|
|
task->tLeft = 15;
|
|
task->tTop = 1;
|
|
task->tWidth = 14;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_BF_RECEPTIONIST:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 10;
|
|
task->tLeft = 17;
|
|
task->tTop = 1;
|
|
task->tWidth = 11;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_BF_MOVE_TUTOR_1:
|
|
case SCROLL_MULTI_BF_MOVE_TUTOR_2:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 11;
|
|
task->tLeft = 15;
|
|
task->tTop = 1;
|
|
task->tWidth = 14;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_SS_TIDAL_DESTINATION:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 7;
|
|
task->tLeft = 19;
|
|
task->tTop = 1;
|
|
task->tWidth = 10;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
case SCROLL_MULTI_BATTLE_TENT_RULES:
|
|
task->tMaxItemsOnScreen = MAX_SCROLL_MULTI_ON_SCREEN;
|
|
task->tNumItems = 7;
|
|
task->tLeft = 17;
|
|
task->tTop = 1;
|
|
task->tWidth = 12;
|
|
task->tHeight = 12;
|
|
task->tKeepOpenAfterSelect = FALSE;
|
|
task->tTaskId = taskId;
|
|
break;
|
|
default:
|
|
gSpecialVar_Result = MULTI_B_PRESSED;
|
|
DestroyTask(taskId);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const u8 *const sScrollableMultichoiceOptions[][MAX_SCROLL_MULTI_LENGTH] =
|
|
{
|
|
[SCROLL_MULTI_NONE] =
|
|
{
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_GLASS_WORKSHOP_VENDOR] =
|
|
{
|
|
gText_BlueFlute,
|
|
gText_YellowFlute,
|
|
gText_RedFlute,
|
|
gText_WhiteFlute,
|
|
gText_BlackFlute,
|
|
gText_PrettyChair,
|
|
gText_PrettyDesk,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_POKEMON_FAN_CLUB_RATER] =
|
|
{
|
|
gText_0Pts,
|
|
gText_10Pts,
|
|
gText_20Pts,
|
|
gText_30Pts,
|
|
gText_40Pts,
|
|
gText_50Pts,
|
|
gText_60Pts,
|
|
gText_70Pts,
|
|
gText_80Pts,
|
|
gText_90Pts,
|
|
gText_100Pts,
|
|
gText_QuestionMark
|
|
},
|
|
[SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_1] =
|
|
{
|
|
gText_KissPoster16BP,
|
|
gText_KissCushion32BP,
|
|
gText_SmoochumDoll32BP,
|
|
gText_TogepiDoll48BP,
|
|
gText_MeowthDoll48BP,
|
|
gText_ClefairyDoll48BP,
|
|
gText_DittoDoll48BP,
|
|
gText_CyndaquilDoll80BP,
|
|
gText_ChikoritaDoll80BP,
|
|
gText_TotodileDoll80BP,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_2] =
|
|
{
|
|
gText_LaprasDoll128BP,
|
|
gText_SnorlaxDoll128BP,
|
|
gText_VenusaurDoll256BP,
|
|
gText_CharizardDoll256BP,
|
|
gText_BlastoiseDoll256BP,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_BF_EXCHANGE_CORNER_VITAMIN_VENDOR] =
|
|
{
|
|
gText_Protein1BP,
|
|
gText_Calcium1BP,
|
|
gText_Iron1BP,
|
|
gText_Zinc1BP,
|
|
gText_Carbos1BP,
|
|
gText_HpUp1BP,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_BF_EXCHANGE_CORNER_HOLD_ITEM_VENDOR] =
|
|
{
|
|
gText_Leftovers48BP,
|
|
gText_WhiteHerb48BP,
|
|
gText_QuickClaw48BP,
|
|
gText_MentalHerb48BP,
|
|
gText_BrightPowder64BP,
|
|
gText_ChoiceBand64BP,
|
|
gText_KingsRock64BP,
|
|
gText_FocusBand64BP,
|
|
gText_ScopeLens64BP,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_BERRY_POWDER_VENDOR] =
|
|
{
|
|
gText_EnergyPowder50,
|
|
gText_EnergyRoot80,
|
|
gText_HealPowder50,
|
|
gText_RevivalHerb300,
|
|
gText_Protein1000,
|
|
gText_Iron1000,
|
|
gText_Carbos1000,
|
|
gText_Calcium1000,
|
|
gText_Zinc1000,
|
|
gText_HPUp1000,
|
|
gText_PPUp3000,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_BF_RECEPTIONIST] =
|
|
{
|
|
gText_BattleTower2,
|
|
gText_BattleDome,
|
|
gText_BattlePalace,
|
|
gText_BattleArena,
|
|
gText_BattleFactory,
|
|
gText_BattlePike,
|
|
gText_BattlePyramid,
|
|
gText_RankingHall,
|
|
gText_ExchangeService,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_BF_MOVE_TUTOR_1] =
|
|
{
|
|
gText_Softboiled16BP,
|
|
gText_SeismicToss24BP,
|
|
gText_DreamEater24BP,
|
|
gText_MegaPunch24BP,
|
|
gText_MegaKick48BP,
|
|
gText_BodySlam48BP,
|
|
gText_RockSlide48BP,
|
|
gText_Counter48BP,
|
|
gText_ThunderWave48BP,
|
|
gText_SwordsDance48BP,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_BF_MOVE_TUTOR_2] =
|
|
{
|
|
gText_DefenseCurl16BP,
|
|
gText_Snore24BP,
|
|
gText_MudSlap24BP,
|
|
gText_Swift24BP,
|
|
gText_IcyWind24BP,
|
|
gText_Endure48BP,
|
|
gText_PsychUp48BP,
|
|
gText_IcePunch48BP,
|
|
gText_ThunderPunch48BP,
|
|
gText_FirePunch48BP,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_SS_TIDAL_DESTINATION] =
|
|
{
|
|
gText_SlateportCity,
|
|
gText_BattleFrontier,
|
|
gText_SouthernIsland,
|
|
gText_NavelRock,
|
|
gText_BirthIsland,
|
|
gText_FarawayIsland,
|
|
gText_Exit
|
|
},
|
|
[SCROLL_MULTI_BATTLE_TENT_RULES] =
|
|
{
|
|
gText_BattleTrainers,
|
|
gText_BattleBasics,
|
|
gText_PokemonNature,
|
|
gText_PokemonMoves,
|
|
gText_Underpowered,
|
|
gText_WhenInDanger,
|
|
gText_Exit
|
|
}
|
|
};
|
|
|
|
static void Task_ShowScrollableMultichoice(u8 taskId)
|
|
{
|
|
u32 width;
|
|
u8 i, windowId;
|
|
struct WindowTemplate template;
|
|
struct Task *task = &gTasks[taskId];
|
|
|
|
LockPlayerFieldControls();
|
|
sScrollableMultichoice_ScrollOffset = 0;
|
|
sScrollableMultichoice_ItemSpriteId = MAX_SPRITES;
|
|
FillFrontierExchangeCornerWindowAndItemIcon(task->tScrollMultiId, 0);
|
|
ShowBattleFrontierTutorWindow(task->tScrollMultiId, 0);
|
|
sScrollableMultichoice_ListMenuItem = AllocZeroed(task->tNumItems * 8);
|
|
sFrontierExchangeCorner_NeverRead = 0;
|
|
InitScrollableMultichoice();
|
|
|
|
for (width = 0, i = 0; i < task->tNumItems; i++)
|
|
{
|
|
const u8 *text = sScrollableMultichoiceOptions[gSpecialVar_0x8004][i];
|
|
sScrollableMultichoice_ListMenuItem[i].name = text;
|
|
sScrollableMultichoice_ListMenuItem[i].id = i;
|
|
width = DisplayTextAndGetWidth(text, width);
|
|
}
|
|
|
|
task->tWidth = ConvertPixelWidthToTileWidth(width);
|
|
|
|
if (task->tLeft + task->tWidth > MAX_MULTICHOICE_WIDTH + 1)
|
|
{
|
|
int adjustedLeft = MAX_MULTICHOICE_WIDTH + 1 - task->tWidth;
|
|
if (adjustedLeft < 0)
|
|
task->tLeft = 0;
|
|
else
|
|
task->tLeft = adjustedLeft;
|
|
}
|
|
|
|
template = CreateWindowTemplate(0, task->tLeft, task->tTop, task->tWidth, task->tHeight, 0xF, 0x64);
|
|
windowId = AddWindow(&template);
|
|
task->tWindowId = windowId;
|
|
SetStandardWindowBorderStyle(windowId, FALSE);
|
|
|
|
gScrollableMultichoice_ListMenuTemplate.totalItems = task->tNumItems;
|
|
gScrollableMultichoice_ListMenuTemplate.maxShowed = task->tMaxItemsOnScreen;
|
|
gScrollableMultichoice_ListMenuTemplate.windowId = task->tWindowId;
|
|
|
|
ScrollableMultichoice_UpdateScrollArrows(taskId);
|
|
task->tListTaskId = ListMenuInit(&gScrollableMultichoice_ListMenuTemplate, task->tScrollOffset, task->tSelectedRow);
|
|
ScheduleBgCopyTilemapToVram(0);
|
|
gTasks[taskId].func = ScrollableMultichoice_ProcessInput;
|
|
}
|
|
|
|
static void InitScrollableMultichoice(void)
|
|
{
|
|
gScrollableMultichoice_ListMenuTemplate.items = sScrollableMultichoice_ListMenuItem;
|
|
gScrollableMultichoice_ListMenuTemplate.moveCursorFunc = ScrollableMultichoice_MoveCursor;
|
|
gScrollableMultichoice_ListMenuTemplate.itemPrintFunc = NULL;
|
|
gScrollableMultichoice_ListMenuTemplate.totalItems = 1;
|
|
gScrollableMultichoice_ListMenuTemplate.maxShowed = 1;
|
|
gScrollableMultichoice_ListMenuTemplate.windowId = 0;
|
|
gScrollableMultichoice_ListMenuTemplate.header_X = 0;
|
|
gScrollableMultichoice_ListMenuTemplate.item_X = 8;
|
|
gScrollableMultichoice_ListMenuTemplate.cursor_X = 0;
|
|
gScrollableMultichoice_ListMenuTemplate.upText_Y = 1;
|
|
gScrollableMultichoice_ListMenuTemplate.cursorPal = 2;
|
|
gScrollableMultichoice_ListMenuTemplate.fillValue = 1;
|
|
gScrollableMultichoice_ListMenuTemplate.cursorShadowPal = 3;
|
|
gScrollableMultichoice_ListMenuTemplate.lettersSpacing = 0;
|
|
gScrollableMultichoice_ListMenuTemplate.itemVerticalPadding = 0;
|
|
gScrollableMultichoice_ListMenuTemplate.scrollMultiple = LIST_NO_MULTIPLE_SCROLL;
|
|
gScrollableMultichoice_ListMenuTemplate.fontId = FONT_NORMAL;
|
|
gScrollableMultichoice_ListMenuTemplate.cursorKind = CURSOR_BLACK_ARROW;
|
|
}
|
|
|
|
static void ScrollableMultichoice_MoveCursor(s32 itemIndex, bool8 onInit, struct ListMenu *list)
|
|
{
|
|
u8 taskId;
|
|
PlaySE(SE_SELECT);
|
|
taskId = FindTaskIdByFunc(ScrollableMultichoice_ProcessInput);
|
|
if (taskId != TASK_NONE)
|
|
{
|
|
u16 selection;
|
|
struct Task *task = &gTasks[taskId];
|
|
ListMenuGetScrollAndRow(task->tListTaskId, &selection, NULL);
|
|
sScrollableMultichoice_ScrollOffset = selection;
|
|
ListMenuGetCurrentItemArrayId(task->tListTaskId, &selection);
|
|
HideFrontierExchangeCornerItemIcon(task->tScrollMultiId, sFrontierExchangeCorner_NeverRead);
|
|
FillFrontierExchangeCornerWindowAndItemIcon(task->tScrollMultiId, selection);
|
|
ShowBattleFrontierTutorMoveDescription(task->tScrollMultiId, selection);
|
|
sFrontierExchangeCorner_NeverRead = selection;
|
|
}
|
|
}
|
|
|
|
static void ScrollableMultichoice_ProcessInput(u8 taskId)
|
|
{
|
|
struct Task *task = &gTasks[taskId];
|
|
s32 input = ListMenu_ProcessInput(task->tListTaskId);
|
|
|
|
switch (input)
|
|
{
|
|
case LIST_NOTHING_CHOSEN:
|
|
break;
|
|
case LIST_CANCEL:
|
|
gSpecialVar_Result = MULTI_B_PRESSED;
|
|
PlaySE(SE_SELECT);
|
|
CloseScrollableMultichoice(taskId);
|
|
break;
|
|
default:
|
|
gSpecialVar_Result = input;
|
|
PlaySE(SE_SELECT);
|
|
if (!task->tKeepOpenAfterSelect)
|
|
{
|
|
CloseScrollableMultichoice(taskId);
|
|
}
|
|
else if (input == task->tNumItems - 1)
|
|
{
|
|
// Selected option was the last one (Exit)
|
|
CloseScrollableMultichoice(taskId);
|
|
}
|
|
else
|
|
{
|
|
// Handle selection while keeping the menu open
|
|
ScrollableMultichoice_RemoveScrollArrows(taskId);
|
|
task->func = Task_ScrollableMultichoice_WaitReturnToList;
|
|
ScriptContext_Enable();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void CloseScrollableMultichoice(u8 taskId)
|
|
{
|
|
u16 selection;
|
|
struct Task *task = &gTasks[taskId];
|
|
ListMenuGetCurrentItemArrayId(task->tListTaskId, &selection);
|
|
HideFrontierExchangeCornerItemIcon(task->tScrollMultiId, selection);
|
|
ScrollableMultichoice_RemoveScrollArrows(taskId);
|
|
DestroyListMenuTask(task->tListTaskId, NULL, NULL);
|
|
Free(sScrollableMultichoice_ListMenuItem);
|
|
ClearStdWindowAndFrameToTransparent(task->tWindowId, TRUE);
|
|
FillWindowPixelBuffer(task->tWindowId, PIXEL_FILL(0));
|
|
CopyWindowToVram(task->tWindowId, COPYWIN_GFX);
|
|
RemoveWindow(task->tWindowId);
|
|
DestroyTask(taskId);
|
|
ScriptContext_Enable();
|
|
}
|
|
|
|
// Never run, tKeepOpenAfterSelect is FALSE for all scrollable multichoices.
|
|
static void Task_ScrollableMultichoice_WaitReturnToList(u8 taskId)
|
|
{
|
|
switch (gTasks[taskId].tKeepOpenAfterSelect)
|
|
{
|
|
case 1:
|
|
default:
|
|
break;
|
|
case 2:
|
|
gTasks[taskId].tKeepOpenAfterSelect = 1;
|
|
gTasks[taskId].func = Task_ScrollableMultichoice_ReturnToList;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Never called
|
|
void ScrollableMultichoice_TryReturnToList(void)
|
|
{
|
|
u8 taskId = FindTaskIdByFunc(Task_ScrollableMultichoice_WaitReturnToList);
|
|
if (taskId == TASK_NONE)
|
|
ScriptContext_Enable();
|
|
else
|
|
gTasks[taskId].tKeepOpenAfterSelect++; // Return to list
|
|
}
|
|
|
|
static void Task_ScrollableMultichoice_ReturnToList(u8 taskId)
|
|
{
|
|
LockPlayerFieldControls();
|
|
ScrollableMultichoice_UpdateScrollArrows(taskId);
|
|
gTasks[taskId].func = ScrollableMultichoice_ProcessInput;
|
|
}
|
|
|
|
static void ScrollableMultichoice_UpdateScrollArrows(u8 taskId)
|
|
{
|
|
static const struct ScrollArrowsTemplate sScrollableMultichoice_ScrollArrowsTemplate = {
|
|
.firstArrowType = SCROLL_ARROW_UP,
|
|
.firstX = 0,
|
|
.firstY = 0,
|
|
.secondArrowType = SCROLL_ARROW_DOWN,
|
|
.secondX = 0,
|
|
.secondY = 0,
|
|
.fullyUpThreshold = 0,
|
|
.fullyDownThreshold = 0,
|
|
.tileTag = GFXTAG_MULTICHOICE_SCROLL_ARROWS,
|
|
.palTag = PALTAG_MULTICHOICE_SCROLL_ARROWS,
|
|
.palNum = 0
|
|
};
|
|
|
|
struct Task *task = &gTasks[taskId];
|
|
struct ScrollArrowsTemplate template = sScrollableMultichoice_ScrollArrowsTemplate;
|
|
if (task->tMaxItemsOnScreen != task->tNumItems)
|
|
{
|
|
template.firstX = (task->tWidth / 2) * 8 + 12 + (task->tLeft - 1) * 8;
|
|
template.firstY = 8;
|
|
template.secondX = (task->tWidth / 2) * 8 + 12 + (task->tLeft - 1) * 8;
|
|
template.secondY = task->tHeight * 8 + 10;
|
|
template.fullyUpThreshold = 0;
|
|
template.fullyDownThreshold = task->tNumItems - task->tMaxItemsOnScreen;
|
|
task->tScrollArrowId = AddScrollIndicatorArrowPair(&template, &sScrollableMultichoice_ScrollOffset);
|
|
}
|
|
}
|
|
|
|
static void ScrollableMultichoice_RemoveScrollArrows(u8 taskId)
|
|
{
|
|
struct Task *task = &gTasks[taskId];
|
|
if (task->tMaxItemsOnScreen != task->tNumItems)
|
|
RemoveScrollIndicatorArrowPair(task->tScrollArrowId);
|
|
}
|
|
|
|
// Removed for Emerald (replaced by ShowScrollableMultichoice)
|
|
void ShowGlassWorkshopMenu(void)
|
|
{
|
|
|
|
}
|
|
|
|
void SetBattleTowerLinkPlayerGfx(void)
|
|
{
|
|
u8 i;
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (gLinkPlayers[i].gender == MALE)
|
|
VarSet(VAR_OBJ_GFX_ID_F - i, OBJ_EVENT_GFX_BRENDAN_NORMAL);
|
|
else
|
|
VarSet(VAR_OBJ_GFX_ID_F - i, OBJ_EVENT_GFX_RIVAL_MAY_NORMAL);
|
|
}
|
|
}
|
|
|
|
void ShowNatureGirlMessage(void)
|
|
{
|
|
static const u8 *const sNatureGirlMessages[NUM_NATURES] = {
|
|
[NATURE_HARDY] = BattleFrontier_Lounge5_Text_NatureGirlHardy,
|
|
[NATURE_LONELY] = BattleFrontier_Lounge5_Text_NatureGirlLonely,
|
|
[NATURE_BRAVE] = BattleFrontier_Lounge5_Text_NatureGirlBrave,
|
|
[NATURE_ADAMANT] = BattleFrontier_Lounge5_Text_NatureGirlAdamant,
|
|
[NATURE_NAUGHTY] = BattleFrontier_Lounge5_Text_NatureGirlNaughty,
|
|
[NATURE_BOLD] = BattleFrontier_Lounge5_Text_NatureGirlBold,
|
|
[NATURE_DOCILE] = BattleFrontier_Lounge5_Text_NatureGirlDocileNaiveQuietQuirky,
|
|
[NATURE_RELAXED] = BattleFrontier_Lounge5_Text_NatureGirlRelaxed,
|
|
[NATURE_IMPISH] = BattleFrontier_Lounge5_Text_NatureGirlImpish,
|
|
[NATURE_LAX] = BattleFrontier_Lounge5_Text_NatureGirlLax,
|
|
[NATURE_TIMID] = BattleFrontier_Lounge5_Text_NatureGirlTimid,
|
|
[NATURE_HASTY] = BattleFrontier_Lounge5_Text_NatureGirlHasty,
|
|
[NATURE_SERIOUS] = BattleFrontier_Lounge5_Text_NatureGirlSerious,
|
|
[NATURE_JOLLY] = BattleFrontier_Lounge5_Text_NatureGirlJolly,
|
|
[NATURE_NAIVE] = BattleFrontier_Lounge5_Text_NatureGirlDocileNaiveQuietQuirky,
|
|
[NATURE_MODEST] = BattleFrontier_Lounge5_Text_NatureGirlModest,
|
|
[NATURE_MILD] = BattleFrontier_Lounge5_Text_NatureGirlMild,
|
|
[NATURE_QUIET] = BattleFrontier_Lounge5_Text_NatureGirlDocileNaiveQuietQuirky,
|
|
[NATURE_BASHFUL] = BattleFrontier_Lounge5_Text_NatureGirlBashful,
|
|
[NATURE_RASH] = BattleFrontier_Lounge5_Text_NatureGirlRash,
|
|
[NATURE_CALM] = BattleFrontier_Lounge5_Text_NatureGirlCalm,
|
|
[NATURE_GENTLE] = BattleFrontier_Lounge5_Text_NatureGirlGentle,
|
|
[NATURE_SASSY] = BattleFrontier_Lounge5_Text_NatureGirlSassy,
|
|
[NATURE_CAREFUL] = BattleFrontier_Lounge5_Text_NatureGirlCareful,
|
|
[NATURE_QUIRKY] = BattleFrontier_Lounge5_Text_NatureGirlDocileNaiveQuietQuirky,
|
|
};
|
|
|
|
u8 nature;
|
|
|
|
if (gSpecialVar_0x8004 >= PARTY_SIZE)
|
|
gSpecialVar_0x8004 = 0;
|
|
|
|
nature = GetNature(&gPlayerParty[gSpecialVar_0x8004]);
|
|
ShowFieldMessage(sNatureGirlMessages[nature]);
|
|
}
|
|
|
|
void UpdateFrontierGambler(u16 daysSince)
|
|
{
|
|
u16 *var = GetVarPointer(VAR_FRONTIER_GAMBLER_CHALLENGE);
|
|
*var += daysSince;
|
|
*var %= FRONTIER_GAMBLER_CHALLENGE_COUNT;
|
|
}
|
|
|
|
void ShowFrontierGamblerLookingMessage(void)
|
|
{
|
|
static const u8 *const sFrontierGamblerLookingMessages[] =
|
|
{
|
|
BattleFrontier_Lounge3_Text_ChallengeBattleTowerSingle,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattleTowerDouble,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattleTowerMulti,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattleDomeSingle,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattleDomeDouble,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattleFactorySingle,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattleFactoryDouble,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattlePalaceSingle,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattlePalaceDouble,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattleArena,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattlePike,
|
|
BattleFrontier_Lounge3_Text_ChallengeBattlePyramid,
|
|
};
|
|
|
|
u16 challenge = VarGet(VAR_FRONTIER_GAMBLER_CHALLENGE);
|
|
ShowFieldMessage(sFrontierGamblerLookingMessages[challenge]);
|
|
VarSet(VAR_FRONTIER_GAMBLER_SET_CHALLENGE, challenge);
|
|
}
|
|
|
|
void ShowFrontierGamblerGoMessage(void)
|
|
{
|
|
static const u8 *const sFrontierGamblerGoMessages[] =
|
|
{
|
|
BattleFrontier_Lounge3_Text_GetToBattleTowerSingle,
|
|
BattleFrontier_Lounge3_Text_GetToBattleTowerDouble,
|
|
BattleFrontier_Lounge3_Text_GetToBattleTowerMulti,
|
|
BattleFrontier_Lounge3_Text_GetToBattleDomeSingle,
|
|
BattleFrontier_Lounge3_Text_GetToBattleDomeDouble,
|
|
BattleFrontier_Lounge3_Text_GetToBattleFactorySingle,
|
|
BattleFrontier_Lounge3_Text_GetToBattleFactoryDouble,
|
|
BattleFrontier_Lounge3_Text_GetToBattlePalaceSingle,
|
|
BattleFrontier_Lounge3_Text_GetToBattlePalaceDouble,
|
|
BattleFrontier_Lounge3_Text_GetToBattleArena,
|
|
BattleFrontier_Lounge3_Text_GetToBattlePike,
|
|
BattleFrontier_Lounge3_Text_GetToBattlePyramid,
|
|
};
|
|
|
|
ShowFieldMessage(sFrontierGamblerGoMessages[VarGet(VAR_FRONTIER_GAMBLER_SET_CHALLENGE)]);
|
|
}
|
|
|
|
void FrontierGamblerSetWonOrLost(bool8 won)
|
|
{
|
|
static const u16 sFrontierChallenges[] =
|
|
{
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_TOWER, FRONTIER_MODE_SINGLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_TOWER, FRONTIER_MODE_DOUBLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_TOWER, FRONTIER_MODE_MULTIS),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_DOME, FRONTIER_MODE_SINGLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_DOME, FRONTIER_MODE_DOUBLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_FACTORY, FRONTIER_MODE_SINGLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_FACTORY, FRONTIER_MODE_DOUBLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_PALACE, FRONTIER_MODE_SINGLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_PALACE, FRONTIER_MODE_DOUBLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_ARENA, FRONTIER_MODE_SINGLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_PIKE, FRONTIER_MODE_SINGLES),
|
|
FRONTIER_CHALLENGE(FRONTIER_FACILITY_PYRAMID, FRONTIER_MODE_SINGLES)
|
|
};
|
|
|
|
u16 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE);
|
|
u16 challenge = VarGet(VAR_FRONTIER_GAMBLER_SET_CHALLENGE);
|
|
u16 frontierFacilityId = VarGet(VAR_FRONTIER_FACILITY);
|
|
|
|
if (VarGet(VAR_FRONTIER_GAMBLER_STATE) == FRONTIER_GAMBLER_PLACED_BET)
|
|
{
|
|
if (sFrontierChallenges[challenge] == FRONTIER_CHALLENGE(frontierFacilityId, battleMode))
|
|
{
|
|
if (won)
|
|
VarSet(VAR_FRONTIER_GAMBLER_STATE, FRONTIER_GAMBLER_WON);
|
|
else
|
|
VarSet(VAR_FRONTIER_GAMBLER_STATE, FRONTIER_GAMBLER_LOST);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateBattlePointsWindow(void)
|
|
{
|
|
u8 string[32];
|
|
u32 x;
|
|
StringCopy(ConvertIntToDecimalStringN(string, gSaveBlock2Ptr->frontier.battlePoints, STR_CONV_MODE_RIGHT_ALIGN, 4), gText_BP);
|
|
x = GetStringRightAlignXOffset(FONT_NORMAL, string, 48);
|
|
AddTextPrinterParameterized(sBattlePointsWindowId, FONT_NORMAL, string, x, 1, 0, NULL);
|
|
}
|
|
|
|
void ShowBattlePointsWindow(void)
|
|
{
|
|
static const struct WindowTemplate sBattlePoints_WindowTemplate =
|
|
{
|
|
.bg = 0,
|
|
.tilemapLeft = 1,
|
|
.tilemapTop = 1,
|
|
.width = 6,
|
|
.height = 2,
|
|
.paletteNum = 15,
|
|
.baseBlock = 8,
|
|
};
|
|
|
|
sBattlePointsWindowId = AddWindow(&sBattlePoints_WindowTemplate);
|
|
SetStandardWindowBorderStyle(sBattlePointsWindowId, FALSE);
|
|
UpdateBattlePointsWindow();
|
|
CopyWindowToVram(sBattlePointsWindowId, COPYWIN_GFX);
|
|
}
|
|
|
|
void CloseBattlePointsWindow(void)
|
|
{
|
|
ClearStdWindowAndFrameToTransparent(sBattlePointsWindowId, TRUE);
|
|
RemoveWindow(sBattlePointsWindowId);
|
|
}
|
|
|
|
void TakeFrontierBattlePoints(void)
|
|
{
|
|
if (gSaveBlock2Ptr->frontier.battlePoints < gSpecialVar_0x8004)
|
|
gSaveBlock2Ptr->frontier.battlePoints = 0;
|
|
else
|
|
gSaveBlock2Ptr->frontier.battlePoints -= gSpecialVar_0x8004;
|
|
}
|
|
|
|
void GiveFrontierBattlePoints(void)
|
|
{
|
|
if (gSaveBlock2Ptr->frontier.battlePoints + gSpecialVar_0x8004 > MAX_BATTLE_FRONTIER_POINTS)
|
|
gSaveBlock2Ptr->frontier.battlePoints = MAX_BATTLE_FRONTIER_POINTS;
|
|
else
|
|
gSaveBlock2Ptr->frontier.battlePoints = gSaveBlock2Ptr->frontier.battlePoints + gSpecialVar_0x8004;
|
|
}
|
|
|
|
u16 GetFrontierBattlePoints(void)
|
|
{
|
|
return gSaveBlock2Ptr->frontier.battlePoints;
|
|
}
|
|
|
|
void ShowFrontierExchangeCornerItemIconWindow(void)
|
|
{
|
|
static const struct WindowTemplate sFrontierExchangeCorner_ItemIconWindowTemplate =
|
|
{
|
|
.bg = 0,
|
|
.tilemapLeft = 2,
|
|
.tilemapTop = 9,
|
|
.width = 4,
|
|
.height = 4,
|
|
.paletteNum = 15,
|
|
.baseBlock = 20,
|
|
};
|
|
|
|
sFrontierExchangeCorner_ItemIconWindowId = AddWindow(&sFrontierExchangeCorner_ItemIconWindowTemplate);
|
|
SetStandardWindowBorderStyle(sFrontierExchangeCorner_ItemIconWindowId, FALSE);
|
|
CopyWindowToVram(sFrontierExchangeCorner_ItemIconWindowId, COPYWIN_GFX);
|
|
}
|
|
|
|
void CloseFrontierExchangeCornerItemIconWindow(void)
|
|
{
|
|
ClearStdWindowAndFrameToTransparent(sFrontierExchangeCorner_ItemIconWindowId, TRUE);
|
|
RemoveWindow(sFrontierExchangeCorner_ItemIconWindowId);
|
|
}
|
|
|
|
static void FillFrontierExchangeCornerWindowAndItemIcon(u16 menu, u16 selection)
|
|
{
|
|
#include "data/battle_frontier/battle_frontier_exchange_corner.h"
|
|
|
|
if (menu >= SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_1 && menu <= SCROLL_MULTI_BF_EXCHANGE_CORNER_HOLD_ITEM_VENDOR)
|
|
{
|
|
FillWindowPixelRect(0, PIXEL_FILL(1), 0, 0, 216, 32);
|
|
switch (menu)
|
|
{
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_1:
|
|
AddTextPrinterParameterized2(0, FONT_NORMAL, sFrontierExchangeCorner_Decor1Descriptions[selection], 0, NULL, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY);
|
|
if (sFrontierExchangeCorner_Decor1[selection] == ITEM_LIST_END)
|
|
{
|
|
ShowFrontierExchangeCornerItemIcon(sFrontierExchangeCorner_Decor1[selection]);
|
|
}
|
|
else
|
|
{
|
|
FreeSpriteTilesByTag(TAG_ITEM_ICON);
|
|
FreeSpritePaletteByTag(TAG_ITEM_ICON);
|
|
sScrollableMultichoice_ItemSpriteId = AddDecorationIconObject(sFrontierExchangeCorner_Decor1[selection], 33, 88, 0, TAG_ITEM_ICON, TAG_ITEM_ICON);
|
|
}
|
|
break;
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_2:
|
|
AddTextPrinterParameterized2(0, FONT_NORMAL, sFrontierExchangeCorner_Decor2Descriptions[selection], 0, NULL, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY);
|
|
if (sFrontierExchangeCorner_Decor2[selection] == ITEM_LIST_END)
|
|
{
|
|
ShowFrontierExchangeCornerItemIcon(sFrontierExchangeCorner_Decor2[selection]);
|
|
}
|
|
else
|
|
{
|
|
FreeSpriteTilesByTag(TAG_ITEM_ICON);
|
|
FreeSpritePaletteByTag(TAG_ITEM_ICON);
|
|
sScrollableMultichoice_ItemSpriteId = AddDecorationIconObject(sFrontierExchangeCorner_Decor2[selection], 33, 88, 0, TAG_ITEM_ICON, TAG_ITEM_ICON);
|
|
}
|
|
break;
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_VITAMIN_VENDOR:
|
|
AddTextPrinterParameterized2(0, FONT_NORMAL, sFrontierExchangeCorner_VitaminsDescriptions[selection], 0, NULL, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY);
|
|
ShowFrontierExchangeCornerItemIcon(sFrontierExchangeCorner_Vitamins[selection]);
|
|
break;
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_HOLD_ITEM_VENDOR:
|
|
AddTextPrinterParameterized2(0, FONT_NORMAL, sFrontierExchangeCorner_HoldItemsDescriptions[selection], 0, NULL, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY);
|
|
ShowFrontierExchangeCornerItemIcon(sFrontierExchangeCorner_HoldItems[selection]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ShowFrontierExchangeCornerItemIcon(u16 item)
|
|
{
|
|
FreeSpriteTilesByTag(TAG_ITEM_ICON);
|
|
FreeSpritePaletteByTag(TAG_ITEM_ICON);
|
|
sScrollableMultichoice_ItemSpriteId = AddItemIconSprite(TAG_ITEM_ICON, TAG_ITEM_ICON, item);
|
|
|
|
if (sScrollableMultichoice_ItemSpriteId != MAX_SPRITES)
|
|
{
|
|
gSprites[sScrollableMultichoice_ItemSpriteId].oam.priority = 0;
|
|
gSprites[sScrollableMultichoice_ItemSpriteId].x = 36;
|
|
gSprites[sScrollableMultichoice_ItemSpriteId].y = 92;
|
|
}
|
|
}
|
|
|
|
static void HideFrontierExchangeCornerItemIcon(u16 menu, u16 unused)
|
|
{
|
|
if (sScrollableMultichoice_ItemSpriteId != MAX_SPRITES)
|
|
{
|
|
switch (menu)
|
|
{
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_1:
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_2:
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_VITAMIN_VENDOR:
|
|
case SCROLL_MULTI_BF_EXCHANGE_CORNER_HOLD_ITEM_VENDOR:
|
|
DestroySpriteAndFreeResources(&gSprites[sScrollableMultichoice_ItemSpriteId]);
|
|
break;
|
|
}
|
|
sScrollableMultichoice_ItemSpriteId = MAX_SPRITES;
|
|
}
|
|
}
|
|
|
|
void BufferBattleFrontierTutorMoveName(void)
|
|
{
|
|
StringCopy(gStringVar1, gMoveNames[gSpecialVar_0x8005]);
|
|
}
|
|
|
|
static void ShowBattleFrontierTutorWindow(u8 menu, u16 selection)
|
|
{
|
|
static const struct WindowTemplate sBattleFrontierTutor_WindowTemplate =
|
|
{
|
|
.bg = 0,
|
|
.tilemapLeft = 1,
|
|
.tilemapTop = 7,
|
|
.width = 12,
|
|
.height = 6,
|
|
.paletteNum = 15,
|
|
.baseBlock = 28,
|
|
};
|
|
|
|
if (menu == SCROLL_MULTI_BF_MOVE_TUTOR_1 || menu == SCROLL_MULTI_BF_MOVE_TUTOR_2)
|
|
{
|
|
if (gSpecialVar_0x8006 == 0)
|
|
{
|
|
sTutorMoveAndElevatorWindowId = AddWindow(&sBattleFrontierTutor_WindowTemplate);
|
|
SetStandardWindowBorderStyle(sTutorMoveAndElevatorWindowId, FALSE);
|
|
}
|
|
ShowBattleFrontierTutorMoveDescription(menu, selection);
|
|
}
|
|
}
|
|
|
|
static void ShowBattleFrontierTutorMoveDescription(u8 menu, u16 selection)
|
|
{
|
|
static const u8 *const sBattleFrontier_TutorMoveDescriptions1[] =
|
|
{
|
|
BattleFrontier_Lounge7_Text_SoftboiledDesc,
|
|
BattleFrontier_Lounge7_Text_SeismicTossDesc,
|
|
BattleFrontier_Lounge7_Text_DreamEaterDesc,
|
|
BattleFrontier_Lounge7_Text_MegaPunchDesc,
|
|
BattleFrontier_Lounge7_Text_MegaKickDesc,
|
|
BattleFrontier_Lounge7_Text_BodySlamDesc,
|
|
BattleFrontier_Lounge7_Text_RockSlideDesc,
|
|
BattleFrontier_Lounge7_Text_CounterDesc,
|
|
BattleFrontier_Lounge7_Text_ThunderWaveDesc,
|
|
BattleFrontier_Lounge7_Text_SwordsDanceDesc,
|
|
gText_Exit,
|
|
};
|
|
|
|
static const u8 *const sBattleFrontier_TutorMoveDescriptions2[] =
|
|
{
|
|
BattleFrontier_Lounge7_Text_DefenseCurlDesc,
|
|
BattleFrontier_Lounge7_Text_SnoreDesc,
|
|
BattleFrontier_Lounge7_Text_MudSlapDesc,
|
|
BattleFrontier_Lounge7_Text_SwiftDesc,
|
|
BattleFrontier_Lounge7_Text_IcyWindDesc,
|
|
BattleFrontier_Lounge7_Text_EndureDesc,
|
|
BattleFrontier_Lounge7_Text_PsychUpDesc,
|
|
BattleFrontier_Lounge7_Text_IcePunchDesc,
|
|
BattleFrontier_Lounge7_Text_ThunderPunchDesc,
|
|
BattleFrontier_Lounge7_Text_FirePunchDesc,
|
|
gText_Exit,
|
|
};
|
|
|
|
if (menu == SCROLL_MULTI_BF_MOVE_TUTOR_1 || menu == SCROLL_MULTI_BF_MOVE_TUTOR_2)
|
|
{
|
|
FillWindowPixelRect(sTutorMoveAndElevatorWindowId, PIXEL_FILL(1), 0, 0, 96, 48);
|
|
if (menu == SCROLL_MULTI_BF_MOVE_TUTOR_2)
|
|
AddTextPrinterParameterized(sTutorMoveAndElevatorWindowId, FONT_NORMAL, sBattleFrontier_TutorMoveDescriptions2[selection], 0, 1, 0, NULL);
|
|
else
|
|
AddTextPrinterParameterized(sTutorMoveAndElevatorWindowId, FONT_NORMAL, sBattleFrontier_TutorMoveDescriptions1[selection], 0, 1, 0, NULL);
|
|
}
|
|
}
|
|
|
|
void CloseBattleFrontierTutorWindow(void)
|
|
{
|
|
ClearStdWindowAndFrameToTransparent(sTutorMoveAndElevatorWindowId, TRUE);
|
|
RemoveWindow(sTutorMoveAndElevatorWindowId);
|
|
}
|
|
|
|
// Never called
|
|
void ScrollableMultichoice_RedrawPersistentMenu(void)
|
|
{
|
|
u16 scrollOffset, selectedRow;
|
|
u8 i;
|
|
u8 taskId = FindTaskIdByFunc(Task_ScrollableMultichoice_WaitReturnToList);
|
|
if (taskId != TASK_NONE)
|
|
{
|
|
struct Task *task = &gTasks[taskId];
|
|
ListMenuGetScrollAndRow(task->tListTaskId, &scrollOffset, &selectedRow);
|
|
SetStandardWindowBorderStyle(task->tWindowId, FALSE);
|
|
|
|
for (i = 0; i < MAX_SCROLL_MULTI_ON_SCREEN; i++)
|
|
AddTextPrinterParameterized5(task->tWindowId, FONT_NORMAL, sScrollableMultichoiceOptions[gSpecialVar_0x8004][scrollOffset + i], 10, i * 16, TEXT_SKIP_DRAW, NULL, 0, 0);
|
|
|
|
AddTextPrinterParameterized(task->tWindowId, FONT_NORMAL, gText_SelectorArrow, 0, selectedRow * 16, TEXT_SKIP_DRAW, NULL);
|
|
PutWindowTilemap(task->tWindowId);
|
|
CopyWindowToVram(task->tWindowId, COPYWIN_FULL);
|
|
}
|
|
}
|
|
|
|
// Never called
|
|
// Close a scrollable multichoice that stays open after selection
|
|
void ScrollableMultichoice_ClosePersistentMenu(void)
|
|
{
|
|
u8 taskId = FindTaskIdByFunc(Task_ScrollableMultichoice_WaitReturnToList);
|
|
if (taskId != TASK_NONE)
|
|
{
|
|
struct Task *task = &gTasks[taskId];
|
|
DestroyListMenuTask(task->tListTaskId, NULL, NULL);
|
|
Free(sScrollableMultichoice_ListMenuItem);
|
|
ClearStdWindowAndFrameToTransparent(task->tWindowId, TRUE);
|
|
FillWindowPixelBuffer(task->tWindowId, PIXEL_FILL(0));
|
|
ClearWindowTilemap(task->tWindowId);
|
|
CopyWindowToVram(task->tWindowId, COPYWIN_GFX);
|
|
RemoveWindow(task->tWindowId);
|
|
DestroyTask(taskId);
|
|
}
|
|
}
|
|
|
|
// Undefine Scrollable Multichoice task data macros
|
|
#undef tMaxItemsOnScreen
|
|
#undef tNumItems
|
|
#undef tLeft
|
|
#undef tTop
|
|
#undef tWidth
|
|
#undef tHeight
|
|
#undef tKeepOpenAfterSelect
|
|
#undef tScrollOffset
|
|
#undef tSelectedRow
|
|
#undef tScrollMultiId
|
|
#undef tScrollArrowId
|
|
#undef tWindowId
|
|
#undef tListTaskId
|
|
#undef tTaskId
|
|
|
|
#define DEOXYS_ROCK_LEVELS 11
|
|
|
|
void DoDeoxysRockInteraction(void)
|
|
{
|
|
CreateTask(Task_DeoxysRockInteraction, 8);
|
|
}
|
|
|
|
static const u16 sDeoxysRockPalettes[DEOXYS_ROCK_LEVELS][16] = {
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_1.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_2.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_3.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_4.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_5.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_6.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_7.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_8.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_9.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_10.gbapal"),
|
|
INCBIN_U16("graphics/field_effects/palettes/deoxys_rock_11.gbapal"),
|
|
};
|
|
|
|
static const u8 sDeoxysRockCoords[DEOXYS_ROCK_LEVELS][2] = {
|
|
{ 15, 12 },
|
|
{ 11, 14 },
|
|
{ 15, 8 },
|
|
{ 19, 14 },
|
|
{ 12, 11 },
|
|
{ 18, 11 },
|
|
{ 15, 14 },
|
|
{ 11, 14 },
|
|
{ 19, 14 },
|
|
{ 15, 15 },
|
|
{ 15, 10 },
|
|
};
|
|
|
|
static void Task_DeoxysRockInteraction(u8 taskId)
|
|
{
|
|
static const u8 sStoneMaxStepCounts[DEOXYS_ROCK_LEVELS - 1] = { 4, 8, 8, 8, 4, 4, 4, 6, 3, 3 };
|
|
|
|
if (FlagGet(FLAG_DEOXYS_ROCK_COMPLETE) == TRUE)
|
|
{
|
|
gSpecialVar_Result = DEOXYS_ROCK_COMPLETE;
|
|
ScriptContext_Enable();
|
|
DestroyTask(taskId);
|
|
}
|
|
else
|
|
{
|
|
u16 rockLevel = VarGet(VAR_DEOXYS_ROCK_LEVEL);
|
|
u16 stepCount = VarGet(VAR_DEOXYS_ROCK_STEP_COUNT);
|
|
|
|
VarSet(VAR_DEOXYS_ROCK_STEP_COUNT, 0);
|
|
if (rockLevel != 0 && sStoneMaxStepCounts[rockLevel - 1] < stepCount)
|
|
{
|
|
// Player failed to take the shortest path to the stone, so it resets.
|
|
ChangeDeoxysRockLevel(0);
|
|
VarSet(VAR_DEOXYS_ROCK_LEVEL, 0);
|
|
gSpecialVar_Result = DEOXYS_ROCK_FAILED;
|
|
DestroyTask(taskId);
|
|
}
|
|
else if (rockLevel == DEOXYS_ROCK_LEVELS - 1)
|
|
{
|
|
FlagSet(FLAG_DEOXYS_ROCK_COMPLETE);
|
|
gSpecialVar_Result = DEOXYS_ROCK_SOLVED;
|
|
ScriptContext_Enable();
|
|
DestroyTask(taskId);
|
|
}
|
|
else
|
|
{
|
|
rockLevel++;
|
|
ChangeDeoxysRockLevel(rockLevel);
|
|
VarSet(VAR_DEOXYS_ROCK_LEVEL, rockLevel);
|
|
gSpecialVar_Result = DEOXYS_ROCK_PROGRESSED;
|
|
DestroyTask(taskId);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ChangeDeoxysRockLevel(u8 rockLevel)
|
|
{
|
|
u8 objectEventId;
|
|
LoadPalette(&sDeoxysRockPalettes[rockLevel], OBJ_PLTT_ID(10), PLTT_SIZEOF(4));
|
|
TryGetObjectEventIdByLocalIdAndMap(LOCALID_BIRTH_ISLAND_EXTERIOR_ROCK, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectEventId);
|
|
|
|
if (rockLevel == 0)
|
|
PlaySE(SE_M_CONFUSE_RAY); // Failure sound
|
|
else
|
|
PlaySE(SE_RG_DEOXYS_MOVE); // Success sound
|
|
|
|
CreateTask(WaitForDeoxysRockMovement, 8);
|
|
gFieldEffectArguments[0] = LOCALID_BIRTH_ISLAND_EXTERIOR_ROCK;
|
|
gFieldEffectArguments[1] = MAP_NUM(BIRTH_ISLAND_EXTERIOR);
|
|
gFieldEffectArguments[2] = MAP_GROUP(BIRTH_ISLAND_EXTERIOR);
|
|
gFieldEffectArguments[3] = sDeoxysRockCoords[rockLevel][0];
|
|
gFieldEffectArguments[4] = sDeoxysRockCoords[rockLevel][1];
|
|
|
|
// Set number of movement steps.
|
|
// Resetting for failure is slow, successful movement is fast.
|
|
if (rockLevel == 0)
|
|
gFieldEffectArguments[5] = 60;
|
|
else
|
|
gFieldEffectArguments[5] = 5;
|
|
|
|
FieldEffectStart(FLDEFF_MOVE_DEOXYS_ROCK);
|
|
SetObjEventTemplateCoords(LOCALID_BIRTH_ISLAND_EXTERIOR_ROCK, sDeoxysRockCoords[rockLevel][0], sDeoxysRockCoords[rockLevel][1]);
|
|
}
|
|
|
|
static void WaitForDeoxysRockMovement(u8 taskId)
|
|
{
|
|
if (FieldEffectActiveListContains(FLDEFF_MOVE_DEOXYS_ROCK) == FALSE)
|
|
{
|
|
ScriptContext_Enable();
|
|
DestroyTask(taskId);
|
|
}
|
|
}
|
|
|
|
void IncrementBirthIslandRockStepCount(void)
|
|
{
|
|
u16 var = VarGet(VAR_DEOXYS_ROCK_STEP_COUNT);
|
|
if (gSaveBlock1Ptr->location.mapNum == MAP_NUM(BIRTH_ISLAND_EXTERIOR) && gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(BIRTH_ISLAND_EXTERIOR))
|
|
{
|
|
var++;
|
|
if (var > 99)
|
|
VarSet(VAR_DEOXYS_ROCK_STEP_COUNT, 0);
|
|
else
|
|
VarSet(VAR_DEOXYS_ROCK_STEP_COUNT, var);
|
|
}
|
|
}
|
|
|
|
void SetDeoxysRockPalette(void)
|
|
{
|
|
LoadPalette(&sDeoxysRockPalettes[(u8)VarGet(VAR_DEOXYS_ROCK_LEVEL)], OBJ_PLTT_ID(10), PLTT_SIZEOF(4));
|
|
BlendPalettes(0x04000000, 16, 0);
|
|
}
|
|
|
|
void SetPCBoxToSendMon(u8 boxId)
|
|
{
|
|
sPCBoxToSendMon = boxId;
|
|
}
|
|
|
|
u16 GetPCBoxToSendMon(void)
|
|
{
|
|
return sPCBoxToSendMon;
|
|
}
|
|
|
|
bool8 ShouldShowBoxWasFullMessage(void)
|
|
{
|
|
if (!FlagGet(FLAG_SHOWN_BOX_WAS_FULL_MESSAGE))
|
|
{
|
|
if (StorageGetCurrentBox() != VarGet(VAR_PC_BOX_TO_SEND_MON))
|
|
{
|
|
FlagSet(FLAG_SHOWN_BOX_WAS_FULL_MESSAGE);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool8 IsDestinationBoxFull(void)
|
|
{
|
|
int box;
|
|
int i;
|
|
SetPCBoxToSendMon(VarGet(VAR_PC_BOX_TO_SEND_MON));
|
|
box = StorageGetCurrentBox();
|
|
do
|
|
{
|
|
for (i = 0; i < IN_BOX_COUNT; i++)
|
|
{
|
|
if (GetBoxMonData(GetBoxedMonPtr(box, i), MON_DATA_SPECIES, 0) == SPECIES_NONE)
|
|
{
|
|
if (GetPCBoxToSendMon() != box)
|
|
FlagClear(FLAG_SHOWN_BOX_WAS_FULL_MESSAGE);
|
|
VarSet(VAR_PC_BOX_TO_SEND_MON, box);
|
|
return ShouldShowBoxWasFullMessage();
|
|
}
|
|
}
|
|
|
|
if (++box == TOTAL_BOXES_COUNT)
|
|
box = 0;
|
|
} while (box != StorageGetCurrentBox());
|
|
return FALSE;
|
|
}
|
|
|
|
void CreateAbnormalWeatherEvent(void)
|
|
{
|
|
u16 randomValue = Random();
|
|
VarSet(VAR_ABNORMAL_WEATHER_STEP_COUNTER, 0);
|
|
|
|
if (FlagGet(FLAG_DEFEATED_KYOGRE) == TRUE)
|
|
{
|
|
VarSet(VAR_ABNORMAL_WEATHER_LOCATION, (randomValue % TERRA_CAVE_LOCATIONS) + TERRA_CAVE_LOCATIONS_START);
|
|
}
|
|
else if (FlagGet(FLAG_DEFEATED_GROUDON) == TRUE)
|
|
{
|
|
VarSet(VAR_ABNORMAL_WEATHER_LOCATION, (randomValue % MARINE_CAVE_LOCATIONS) + MARINE_CAVE_LOCATIONS_START);
|
|
}
|
|
else if ((randomValue & 1) == 0)
|
|
{
|
|
randomValue = Random();
|
|
VarSet(VAR_ABNORMAL_WEATHER_LOCATION, (randomValue % TERRA_CAVE_LOCATIONS) + TERRA_CAVE_LOCATIONS_START);
|
|
}
|
|
else
|
|
{
|
|
randomValue = Random();
|
|
VarSet(VAR_ABNORMAL_WEATHER_LOCATION, (randomValue % MARINE_CAVE_LOCATIONS) + MARINE_CAVE_LOCATIONS_START);
|
|
}
|
|
}
|
|
|
|
// Saves the map name for the current abnormal weather location in gStringVar1, then
|
|
// returns TRUE if the weather is for Kyogre, and FALSE if it's for Groudon.
|
|
bool32 GetAbnormalWeatherMapNameAndType(void)
|
|
{
|
|
static const u8 sAbnormalWeatherMapNumbers[] = {
|
|
MAP_NUM(ROUTE114),
|
|
MAP_NUM(ROUTE114),
|
|
MAP_NUM(ROUTE115),
|
|
MAP_NUM(ROUTE115),
|
|
MAP_NUM(ROUTE116),
|
|
MAP_NUM(ROUTE116),
|
|
MAP_NUM(ROUTE118),
|
|
MAP_NUM(ROUTE118),
|
|
MAP_NUM(ROUTE105),
|
|
MAP_NUM(ROUTE105),
|
|
MAP_NUM(ROUTE125),
|
|
MAP_NUM(ROUTE125),
|
|
MAP_NUM(ROUTE127),
|
|
MAP_NUM(ROUTE127),
|
|
MAP_NUM(ROUTE129),
|
|
MAP_NUM(ROUTE129)
|
|
};
|
|
|
|
u16 abnormalWeather = VarGet(VAR_ABNORMAL_WEATHER_LOCATION);
|
|
|
|
GetMapName(gStringVar1, sAbnormalWeatherMapNumbers[abnormalWeather - 1], 0);
|
|
|
|
if (abnormalWeather < MARINE_CAVE_LOCATIONS_START)
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
bool8 AbnormalWeatherHasExpired(void)
|
|
{
|
|
// Duplicate array.
|
|
static const u8 sAbnormalWeatherMapNumbers[] =
|
|
{
|
|
MAP_NUM(ROUTE114),
|
|
MAP_NUM(ROUTE114),
|
|
MAP_NUM(ROUTE115),
|
|
MAP_NUM(ROUTE115),
|
|
MAP_NUM(ROUTE116),
|
|
MAP_NUM(ROUTE116),
|
|
MAP_NUM(ROUTE118),
|
|
MAP_NUM(ROUTE118),
|
|
MAP_NUM(ROUTE105),
|
|
MAP_NUM(ROUTE105),
|
|
MAP_NUM(ROUTE125),
|
|
MAP_NUM(ROUTE125),
|
|
MAP_NUM(ROUTE127),
|
|
MAP_NUM(ROUTE127),
|
|
MAP_NUM(ROUTE129),
|
|
MAP_NUM(ROUTE129)
|
|
};
|
|
|
|
u16 steps = VarGet(VAR_ABNORMAL_WEATHER_STEP_COUNTER);
|
|
u16 abnormalWeather = VarGet(VAR_ABNORMAL_WEATHER_LOCATION);
|
|
|
|
if (abnormalWeather == ABNORMAL_WEATHER_NONE)
|
|
return FALSE;
|
|
|
|
if (++steps > 999)
|
|
{
|
|
VarSet(VAR_ABNORMAL_WEATHER_STEP_COUNTER, 0);
|
|
if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(UNDERWATER_MARINE_CAVE))
|
|
{
|
|
switch (gSaveBlock1Ptr->location.mapNum)
|
|
{
|
|
case MAP_NUM(UNDERWATER_MARINE_CAVE):
|
|
case MAP_NUM(MARINE_CAVE_ENTRANCE):
|
|
case MAP_NUM(MARINE_CAVE_END):
|
|
case MAP_NUM(TERRA_CAVE_ENTRANCE):
|
|
case MAP_NUM(TERRA_CAVE_END):
|
|
VarSet(VAR_SHOULD_END_ABNORMAL_WEATHER, 1);
|
|
return FALSE;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(UNDERWATER_ROUTE127))
|
|
{
|
|
switch (gSaveBlock1Ptr->location.mapNum)
|
|
{
|
|
case MAP_NUM(UNDERWATER_ROUTE127):
|
|
case MAP_NUM(UNDERWATER_ROUTE129):
|
|
case MAP_NUM(UNDERWATER_ROUTE105):
|
|
case MAP_NUM(UNDERWATER_ROUTE125):
|
|
VarSet(VAR_SHOULD_END_ABNORMAL_WEATHER, 1);
|
|
return FALSE;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (gSaveBlock1Ptr->location.mapNum == sAbnormalWeatherMapNumbers[abnormalWeather - 1] &&
|
|
gSaveBlock1Ptr->location.mapGroup == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
VarSet(VAR_ABNORMAL_WEATHER_LOCATION, ABNORMAL_WEATHER_NONE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VarSet(VAR_ABNORMAL_WEATHER_STEP_COUNTER, steps);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
void Unused_SetWeatherSunny(void)
|
|
{
|
|
SetCurrentAndNextWeather(WEATHER_SUNNY);
|
|
}
|
|
|
|
// All mart employees have a local id of 1, so function always returns 1
|
|
u32 GetMartEmployeeObjectEventId(void)
|
|
{
|
|
static const u8 sPokeMarts[][3] =
|
|
{
|
|
{ MAP_GROUP(OLDALE_TOWN_MART), MAP_NUM(OLDALE_TOWN_MART), LOCALID_OLDALE_MART_CLERK },
|
|
{ MAP_GROUP(LAVARIDGE_TOWN_MART), MAP_NUM(LAVARIDGE_TOWN_MART), LOCALID_LAVARIDGE_MART_CLERK },
|
|
{ MAP_GROUP(FALLARBOR_TOWN_MART), MAP_NUM(FALLARBOR_TOWN_MART), LOCALID_FALLARBOR_MART_CLERK },
|
|
{ MAP_GROUP(VERDANTURF_TOWN_MART), MAP_NUM(VERDANTURF_TOWN_MART), LOCALID_VERDANTURF_MART_CLERK },
|
|
{ MAP_GROUP(PETALBURG_CITY_MART), MAP_NUM(PETALBURG_CITY_MART), LOCALID_PETALBURG_MART_CLERK },
|
|
{ MAP_GROUP(SLATEPORT_CITY_MART), MAP_NUM(SLATEPORT_CITY_MART), LOCALID_SLATEPORT_MART_CLERK },
|
|
{ MAP_GROUP(MAUVILLE_CITY_MART), MAP_NUM(MAUVILLE_CITY_MART), LOCALID_MAUVILLE_MART_CLERK },
|
|
{ MAP_GROUP(RUSTBORO_CITY_MART), MAP_NUM(RUSTBORO_CITY_MART), LOCALID_RUSTBORO_MART_CLERK },
|
|
{ MAP_GROUP(FORTREE_CITY_MART), MAP_NUM(FORTREE_CITY_MART), LOCALID_FORTREE_MART_CLERK },
|
|
{ MAP_GROUP(MOSSDEEP_CITY_MART), MAP_NUM(MOSSDEEP_CITY_MART), LOCALID_MOSSDEEP_MART_CLERK },
|
|
{ MAP_GROUP(SOOTOPOLIS_CITY_MART), MAP_NUM(SOOTOPOLIS_CITY_MART), LOCALID_SOOTOPOLIS_MART_CLERK },
|
|
{ MAP_GROUP(BATTLE_FRONTIER_MART), MAP_NUM(BATTLE_FRONTIER_MART), LOCALID_BATTLE_FRONTIER_MART_CLERK }
|
|
};
|
|
|
|
u8 i;
|
|
for (i = 0; i < ARRAY_COUNT(sPokeMarts); i++)
|
|
{
|
|
if (gSaveBlock1Ptr->location.mapGroup == sPokeMarts[i][0])
|
|
{
|
|
if (gSaveBlock1Ptr->location.mapNum == sPokeMarts[i][1])
|
|
return sPokeMarts[i][2];
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
bool32 IsTrainerRegistered(void)
|
|
{
|
|
int index = GetRematchIdxByTrainerIdx(gSpecialVar_0x8004);
|
|
if (index >= 0)
|
|
{
|
|
if (FlagGet(FLAG_MATCH_CALL_REGISTERED + index) == TRUE)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Always returns FALSE
|
|
bool32 ShouldDistributeEonTicket(void)
|
|
{
|
|
if (!VarGet(VAR_DISTRIBUTE_EON_TICKET))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#define tState data[0]
|
|
|
|
void BattleTowerReconnectLink(void)
|
|
{
|
|
// Save battle type, restored at end
|
|
// of Task_LinkRetireStatusWithBattleTowerPartner
|
|
sBattleTowerMultiBattleTypeFlags = gBattleTypeFlags;
|
|
gBattleTypeFlags = 0;
|
|
|
|
if (!gReceivedRemoteLinkPlayers)
|
|
CreateTask(Task_ReconnectWithLinkPlayers, 5);
|
|
}
|
|
|
|
void LinkRetireStatusWithBattleTowerPartner(void)
|
|
{
|
|
CreateTask(Task_LinkRetireStatusWithBattleTowerPartner, 5);
|
|
}
|
|
|
|
// Communicate with a Battle Tower link partner to tell them
|
|
// whether or not the player chose to continue or retire,
|
|
// and determine what the partner chose to do
|
|
// gSpecialVar_0x8004: Player's choice
|
|
// gSpecialVar_0x8005: Partner's choice (read from gBlockRecvBuffer[1][0])
|
|
static void Task_LinkRetireStatusWithBattleTowerPartner(u8 taskId)
|
|
{
|
|
switch (gTasks[taskId].tState)
|
|
{
|
|
case 0:
|
|
if (!FuncIsActiveTask(Task_ReconnectWithLinkPlayers))
|
|
gTasks[taskId].tState++;
|
|
break;
|
|
case 1:
|
|
if (IsLinkTaskFinished() == TRUE)
|
|
{
|
|
if (GetMultiplayerId() == 0)
|
|
{
|
|
// Player is link leader, skip sending data
|
|
gTasks[taskId].tState++;
|
|
}
|
|
else
|
|
{
|
|
// Send value of gSpecialVar_0x8004 to leader
|
|
// Will either be BATTLE_TOWER_LINK_CONTINUE or BATTLE_TOWER_LINK_RETIRE
|
|
SendBlock(BitmaskAllOtherLinkPlayers(), &gSpecialVar_0x8004, sizeof(gSpecialVar_0x8004));
|
|
gTasks[taskId].tState++;
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
if (GetBlockReceivedStatus() & 2)
|
|
{
|
|
if (GetMultiplayerId() == 0)
|
|
{
|
|
// Player is leader, read partner's choice
|
|
// and determine if play should continue
|
|
gSpecialVar_0x8005 = gBlockRecvBuffer[1][0];
|
|
ResetBlockReceivedFlag(1);
|
|
|
|
if (gSpecialVar_0x8004 == BATTLE_TOWER_LINK_RETIRE
|
|
&& gSpecialVar_0x8005 == BATTLE_TOWER_LINK_RETIRE)
|
|
gSpecialVar_Result = BATTLE_TOWER_LINKSTAT_BOTH_RETIRE;
|
|
else if (gSpecialVar_0x8004 == BATTLE_TOWER_LINK_CONTINUE
|
|
&& gSpecialVar_0x8005 == BATTLE_TOWER_LINK_RETIRE)
|
|
gSpecialVar_Result = BATTLE_TOWER_LINKSTAT_MEMBER_RETIRE;
|
|
else if (gSpecialVar_0x8004 == BATTLE_TOWER_LINK_RETIRE
|
|
&& gSpecialVar_0x8005 == BATTLE_TOWER_LINK_CONTINUE)
|
|
gSpecialVar_Result = BATTLE_TOWER_LINKSTAT_LEADER_RETIRE;
|
|
else
|
|
gSpecialVar_Result = BATTLE_TOWER_LINKSTAT_CONTINUE;
|
|
}
|
|
gTasks[taskId].tState++;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (IsLinkTaskFinished() == TRUE)
|
|
{
|
|
if (GetMultiplayerId() != 0)
|
|
{
|
|
// Player is not link leader, wait for leader's response
|
|
gTasks[taskId].tState++;
|
|
}
|
|
else
|
|
{
|
|
// Send whether or not play should continue
|
|
SendBlock(BitmaskAllOtherLinkPlayers(), &gSpecialVar_Result, sizeof(gSpecialVar_Result));
|
|
gTasks[taskId].tState++;
|
|
}
|
|
}
|
|
break;
|
|
case 4:
|
|
if (GetBlockReceivedStatus() & 1)
|
|
{
|
|
if (GetMultiplayerId() != 0)
|
|
{
|
|
// Player is not link leader, read leader's response
|
|
gSpecialVar_Result = gBlockRecvBuffer[0][0];
|
|
ResetBlockReceivedFlag(0);
|
|
gTasks[taskId].tState++;
|
|
}
|
|
else
|
|
{
|
|
gTasks[taskId].tState++;
|
|
}
|
|
}
|
|
break;
|
|
case 5:
|
|
// Print message if partner chose to retire (and player didn't)
|
|
if (GetMultiplayerId() == 0)
|
|
{
|
|
if (gSpecialVar_Result == BATTLE_TOWER_LINKSTAT_MEMBER_RETIRE)
|
|
ShowFieldAutoScrollMessage(gText_YourPartnerHasRetired);
|
|
}
|
|
else
|
|
{
|
|
if (gSpecialVar_Result == BATTLE_TOWER_LINKSTAT_LEADER_RETIRE)
|
|
ShowFieldAutoScrollMessage(gText_YourPartnerHasRetired);
|
|
}
|
|
gTasks[taskId].tState++;
|
|
break;
|
|
case 6:
|
|
if (!IsTextPrinterActive(0))
|
|
gTasks[taskId].tState++;
|
|
break;
|
|
case 7:
|
|
if (IsLinkTaskFinished() == TRUE)
|
|
{
|
|
SetLinkStandbyCallback();
|
|
gTasks[taskId].tState++;
|
|
}
|
|
break;
|
|
case 8:
|
|
if (IsLinkTaskFinished() == TRUE)
|
|
gTasks[taskId].tState++;
|
|
break;
|
|
case 9:
|
|
if (gWirelessCommType == 0)
|
|
SetCloseLinkCallback();
|
|
|
|
gBattleTypeFlags = sBattleTowerMultiBattleTypeFlags;
|
|
ScriptContext_Enable();
|
|
DestroyTask(taskId);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#undef tState
|
|
|
|
void Script_DoRayquazaScene(void)
|
|
{
|
|
if (!gSpecialVar_0x8004)
|
|
{
|
|
// Groudon/Kyogre fight scene
|
|
DoRayquazaScene(0, TRUE, CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
|
}
|
|
else
|
|
{
|
|
// Rayquaza arrives scene
|
|
DoRayquazaScene(1, FALSE, CB2_ReturnToFieldContinueScriptPlayMapMusic);
|
|
}
|
|
}
|
|
|
|
#define playCount data[0]
|
|
#define delay data[1]
|
|
|
|
void LoopWingFlapSE(void)
|
|
{
|
|
CreateTask(Task_LoopWingFlapSE, 8);
|
|
PlaySE(SE_M_WING_ATTACK);
|
|
}
|
|
|
|
static void Task_LoopWingFlapSE(u8 taskId)
|
|
{
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
delay++;
|
|
if (delay == gSpecialVar_0x8005)
|
|
{
|
|
playCount++;
|
|
delay = 0;
|
|
PlaySE(SE_M_WING_ATTACK);
|
|
}
|
|
|
|
if (playCount == gSpecialVar_0x8004 - 1)
|
|
DestroyTask(taskId);
|
|
}
|
|
|
|
#undef playCount
|
|
#undef delay
|
|
|
|
#define CURTAIN_HEIGHT 4
|
|
#define CURTAIN_WIDTH 3
|
|
#define tFrameTimer data
|
|
#define tCurrentFrame data[3]
|
|
|
|
void CloseBattlePikeCurtain(void)
|
|
{
|
|
u8 taskId = CreateTask(Task_CloseBattlePikeCurtain, 8);
|
|
gTasks[taskId].tFrameTimer[0] = 4;
|
|
gTasks[taskId].tFrameTimer[1] = 4;
|
|
gTasks[taskId].tFrameTimer[2] = 4;
|
|
gTasks[taskId].tCurrentFrame = 0;
|
|
}
|
|
|
|
static void Task_CloseBattlePikeCurtain(u8 taskId)
|
|
{
|
|
u8 x, y;
|
|
s16 *data = gTasks[taskId].data;
|
|
|
|
tFrameTimer[tCurrentFrame]--;
|
|
if (tFrameTimer[tCurrentFrame] == 0)
|
|
{
|
|
for (y = 0; y < CURTAIN_HEIGHT; y++)
|
|
{
|
|
for (x = 0; x < CURTAIN_WIDTH; x++)
|
|
{
|
|
MapGridSetMetatileIdAt(gSaveBlock1Ptr->pos.x + x + MAP_OFFSET - 1,
|
|
gSaveBlock1Ptr->pos.y + y + MAP_OFFSET - 3,
|
|
(x + METATILE_BattlePike_CurtainFrames_Start) + (y * METATILE_ROW_WIDTH) + (tCurrentFrame * CURTAIN_HEIGHT * METATILE_ROW_WIDTH));
|
|
}
|
|
}
|
|
DrawWholeMapView();
|
|
tCurrentFrame++;
|
|
if (tCurrentFrame == 3)
|
|
{
|
|
DestroyTask(taskId);
|
|
ScriptContext_Enable();
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef CURTAIN_HEIGHT
|
|
#undef CURTAIN_WIDTH
|
|
#undef tFrameTimer
|
|
#undef tCurrentFrame
|
|
|
|
void GetBattlePyramidHint(void)
|
|
{
|
|
// gSpecialVar_0x8004 here is expected to be the current Battle Pyramid win streak.
|
|
gSpecialVar_Result = gSpecialVar_0x8004 / FRONTIER_STAGES_PER_CHALLENGE;
|
|
gSpecialVar_Result -= (gSpecialVar_Result / TOTAL_PYRAMID_ROUNDS) * TOTAL_PYRAMID_ROUNDS;
|
|
}
|
|
|
|
// Used to avoid a potential softlock if the player respawns on Dewford with no way off
|
|
void ResetHealLocationFromDewford(void)
|
|
{
|
|
if (gSaveBlock1Ptr->lastHealLocation.mapGroup == MAP_GROUP(DEWFORD_TOWN) && gSaveBlock1Ptr->lastHealLocation.mapNum == MAP_NUM(DEWFORD_TOWN))
|
|
SetLastHealLocationWarp(HEAL_LOCATION_PETALBURG_CITY);
|
|
}
|
|
|
|
bool8 InPokemonCenter(void)
|
|
{
|
|
static const u16 sPokemonCenters[] =
|
|
{
|
|
MAP_OLDALE_TOWN_POKEMON_CENTER_1F,
|
|
MAP_DEWFORD_TOWN_POKEMON_CENTER_1F,
|
|
MAP_LAVARIDGE_TOWN_POKEMON_CENTER_1F,
|
|
MAP_FALLARBOR_TOWN_POKEMON_CENTER_1F,
|
|
MAP_VERDANTURF_TOWN_POKEMON_CENTER_1F,
|
|
MAP_PACIFIDLOG_TOWN_POKEMON_CENTER_1F,
|
|
MAP_PETALBURG_CITY_POKEMON_CENTER_1F,
|
|
MAP_SLATEPORT_CITY_POKEMON_CENTER_1F,
|
|
MAP_MAUVILLE_CITY_POKEMON_CENTER_1F,
|
|
MAP_RUSTBORO_CITY_POKEMON_CENTER_1F,
|
|
MAP_FORTREE_CITY_POKEMON_CENTER_1F,
|
|
MAP_LILYCOVE_CITY_POKEMON_CENTER_1F,
|
|
MAP_MOSSDEEP_CITY_POKEMON_CENTER_1F,
|
|
MAP_SOOTOPOLIS_CITY_POKEMON_CENTER_1F,
|
|
MAP_EVER_GRANDE_CITY_POKEMON_CENTER_1F,
|
|
MAP_EVER_GRANDE_CITY_POKEMON_LEAGUE_1F,
|
|
MAP_BATTLE_FRONTIER_POKEMON_CENTER_1F,
|
|
MAP_BATTLE_COLOSSEUM_2P,
|
|
MAP_TRADE_CENTER,
|
|
MAP_RECORD_CORNER,
|
|
MAP_BATTLE_COLOSSEUM_4P,
|
|
MAP_UNDEFINED
|
|
};
|
|
|
|
int i;
|
|
u16 map = (gSaveBlock1Ptr->location.mapGroup << 8) + gSaveBlock1Ptr->location.mapNum;
|
|
|
|
for (i = 0; sPokemonCenters[i] != MAP_UNDEFINED; i++)
|
|
{
|
|
if (sPokemonCenters[i] == map)
|
|
return TRUE;
|
|
}
|
|
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_FAN_COUNTER - VARS_START] = 0;
|
|
gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] = 0;
|
|
}
|
|
|
|
void TryLoseFansFromPlayTimeAfterLinkBattle(void)
|
|
{
|
|
if (DidPlayerGetFirstFans())
|
|
{
|
|
TryLoseFansFromPlayTime();
|
|
gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] = gSaveBlock2Ptr->playTimeHours;
|
|
}
|
|
}
|
|
|
|
void UpdateTrainerFanClubGameClear(void)
|
|
{
|
|
if (!GET_TRAINER_FAN_CLUB_FLAG(FANCLUB_GOT_FIRST_FANS))
|
|
{
|
|
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);
|
|
FlagClear(FLAG_HIDE_FANCLUB_LADY);
|
|
FlagClear(FLAG_HIDE_LILYCOVE_FAN_CLUB_INTERVIEWER);
|
|
VarSet(VAR_LILYCOVE_FAN_CLUB_STATE, 1);
|
|
}
|
|
}
|
|
|
|
// If the player has < 3 fans, gain a new fan whenever the counter reaches 20+
|
|
// Defeating Drake or participating in a 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 sCounterIncrements[] =
|
|
{
|
|
[FANCOUNTER_DEFEATED_DRAKE] = 2,
|
|
[FANCOUNTER_BATTLED_AT_BASE] = 1,
|
|
[FANCOUNTER_FINISHED_CONTEST] = 2,
|
|
[FANCOUNTER_USED_BATTLE_TOWER] = 1
|
|
};
|
|
|
|
if (VarGet(VAR_LILYCOVE_FAN_CLUB_STATE) == 2)
|
|
{
|
|
if (GET_TRAINER_FAN_CLUB_COUNTER + sCounterIncrements[incrementId] > 19)
|
|
{
|
|
if (GetNumFansOfPlayerInTrainerFanClub() < 3)
|
|
{
|
|
PlayerGainRandomTrainerFan();
|
|
CLEAR_TRAINER_FAN_CLUB_COUNTER;
|
|
}
|
|
else
|
|
{
|
|
SET_TRAINER_FAN_CLUB_COUNTER(20);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
INCR_TRAINER_FAN_CLUB_COUNTER(sCounterIncrements[incrementId]);
|
|
}
|
|
}
|
|
|
|
return GET_TRAINER_FAN_CLUB_COUNTER;
|
|
}
|
|
|
|
|
|
// 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 sFanClubMemberIds[NUM_TRAINER_FAN_CLUB_MEMBERS] =
|
|
{
|
|
FANCLUB_MEMBER1,
|
|
FANCLUB_MEMBER2,
|
|
FANCLUB_MEMBER3,
|
|
FANCLUB_MEMBER4,
|
|
FANCLUB_MEMBER5,
|
|
FANCLUB_MEMBER6,
|
|
FANCLUB_MEMBER7,
|
|
FANCLUB_MEMBER8
|
|
};
|
|
|
|
u8 i;
|
|
u8 idx = 0;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sFanClubMemberIds); i++)
|
|
{
|
|
if (!GET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[i]))
|
|
{
|
|
idx = i;
|
|
if (Random() & 1)
|
|
{
|
|
SET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]);
|
|
return idx;
|
|
}
|
|
}
|
|
}
|
|
SET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]);
|
|
return idx;
|
|
}
|
|
|
|
// 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 sFanClubMemberIds[NUM_TRAINER_FAN_CLUB_MEMBERS] =
|
|
{
|
|
FANCLUB_MEMBER1,
|
|
FANCLUB_MEMBER6,
|
|
FANCLUB_MEMBER7,
|
|
FANCLUB_MEMBER4,
|
|
FANCLUB_MEMBER3,
|
|
FANCLUB_MEMBER5,
|
|
FANCLUB_MEMBER8,
|
|
FANCLUB_MEMBER2
|
|
};
|
|
|
|
u8 i;
|
|
u8 idx = 0;
|
|
|
|
if (GetNumFansOfPlayerInTrainerFanClub() == 1)
|
|
return 0;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(sFanClubMemberIds); i++)
|
|
{
|
|
if (GET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[i]))
|
|
{
|
|
idx = i;
|
|
if (Random() & 1)
|
|
{
|
|
FLIP_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]);
|
|
return idx;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GET_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]))
|
|
FLIP_TRAINER_FAN_CLUB_FLAG(sFanClubMemberIds[idx]);
|
|
|
|
return idx;
|
|
}
|
|
|
|
u16 GetNumFansOfPlayerInTrainerFanClub(void)
|
|
{
|
|
u8 i;
|
|
u8 numFans = 0;
|
|
|
|
for (i = 0; i < NUM_TRAINER_FAN_CLUB_MEMBERS; i++)
|
|
{
|
|
if (GET_TRAINER_FAN_CLUB_FLAG(i + FANCLUB_MEMBER1))
|
|
numFans++;
|
|
}
|
|
|
|
return numFans;
|
|
}
|
|
|
|
// 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 (GetNumFansOfPlayerInTrainerFanClub() < 5)
|
|
{
|
|
gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] = gSaveBlock2Ptr->playTimeHours;
|
|
break;
|
|
}
|
|
else if (i == NUM_TRAINER_FAN_CLUB_MEMBERS)
|
|
{
|
|
break;
|
|
}
|
|
else if (gSaveBlock2Ptr->playTimeHours - gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] < 12)
|
|
{
|
|
return;
|
|
}
|
|
PlayerLoseRandomTrainerFan();
|
|
gSaveBlock1Ptr->vars[VAR_FANCLUB_LOSE_FAN_TIMER - VARS_START] += 12;
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool8 IsFanClubMemberFanOfPlayer(void)
|
|
{
|
|
return GET_TRAINER_FAN_CLUB_FLAG(gSpecialVar_0x8004);
|
|
}
|
|
|
|
static void SetInitialFansOfPlayer(void)
|
|
{
|
|
SET_TRAINER_FAN_CLUB_FLAG(FANCLUB_MEMBER6);
|
|
SET_TRAINER_FAN_CLUB_FLAG(FANCLUB_MEMBER1);
|
|
SET_TRAINER_FAN_CLUB_FLAG(FANCLUB_MEMBER3);
|
|
}
|
|
|
|
void BufferFanClubTrainerName(void)
|
|
{
|
|
u8 whichLinkTrainer = 0;
|
|
u8 whichNPCTrainer = 0;
|
|
switch (gSpecialVar_0x8004)
|
|
{
|
|
case FANCLUB_MEMBER1:
|
|
break;
|
|
case FANCLUB_MEMBER2:
|
|
break;
|
|
case FANCLUB_MEMBER3:
|
|
whichLinkTrainer = 0;
|
|
whichNPCTrainer = 3;
|
|
break;
|
|
case FANCLUB_MEMBER4:
|
|
whichLinkTrainer = 0;
|
|
whichNPCTrainer = 1;
|
|
break;
|
|
case FANCLUB_MEMBER5:
|
|
whichLinkTrainer = 1;
|
|
whichNPCTrainer = 0;
|
|
break;
|
|
case FANCLUB_MEMBER6:
|
|
whichLinkTrainer = 0;
|
|
whichNPCTrainer = 4;
|
|
break;
|
|
case FANCLUB_MEMBER7:
|
|
whichLinkTrainer = 1;
|
|
whichNPCTrainer = 5;
|
|
break;
|
|
case FANCLUB_MEMBER8:
|
|
break;
|
|
}
|
|
BufferFanClubTrainerName_(&gSaveBlock1Ptr->linkBattleRecords, whichLinkTrainer, whichNPCTrainer);
|
|
}
|
|
|
|
static void BufferFanClubTrainerName_(struct LinkBattleRecords *linkRecords, u8 whichLinkTrainer, u8 whichNPCTrainer)
|
|
{
|
|
struct LinkBattleRecord *record = &linkRecords->entries[whichLinkTrainer];
|
|
if (record->name[0] == EOS)
|
|
{
|
|
switch (whichNPCTrainer)
|
|
{
|
|
case 0:
|
|
StringCopy(gStringVar1, gText_Wallace);
|
|
break;
|
|
case 1:
|
|
StringCopy(gStringVar1, gText_Steven);
|
|
break;
|
|
case 2:
|
|
StringCopy(gStringVar1, gText_Brawly);
|
|
break;
|
|
case 3:
|
|
StringCopy(gStringVar1, gText_Winona);
|
|
break;
|
|
case 4:
|
|
StringCopy(gStringVar1, gText_Phoebe);
|
|
break;
|
|
case 5:
|
|
StringCopy(gStringVar1, gText_Glacia);
|
|
break;
|
|
default:
|
|
StringCopy(gStringVar1, gText_Wallace);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StringCopyN(gStringVar1, record->name, PLAYER_NAME_LENGTH);
|
|
gStringVar1[PLAYER_NAME_LENGTH] = EOS;
|
|
ConvertInternationalString(gStringVar1, linkRecords->languages[whichLinkTrainer]);
|
|
}
|
|
}
|
|
|
|
void UpdateTrainerFansAfterLinkBattle(void)
|
|
{
|
|
if (VarGet(VAR_LILYCOVE_FAN_CLUB_STATE) == 2)
|
|
{
|
|
TryLoseFansFromPlayTimeAfterLinkBattle();
|
|
if (gBattleOutcome == B_OUTCOME_WON)
|
|
PlayerGainRandomTrainerFan();
|
|
else
|
|
PlayerLoseRandomTrainerFan();
|
|
}
|
|
}
|
|
|
|
static bool8 DidPlayerGetFirstFans(void)
|
|
{
|
|
return GET_TRAINER_FAN_CLUB_FLAG(FANCLUB_GOT_FIRST_FANS);
|
|
}
|
|
|
|
void SetPlayerGotFirstFans(void)
|
|
{
|
|
SET_TRAINER_FAN_CLUB_FLAG(FANCLUB_GOT_FIRST_FANS);
|
|
}
|
|
|
|
// return value is always ignored
|
|
u8 Script_TryGainNewFanFromCounter(void)
|
|
{
|
|
return TryGainNewFanFromCounter(gSpecialVar_0x8004);
|
|
}
|