pokeemerald/src/field_special_scene.c

386 lines
12 KiB
C
Raw Normal View History

2017-09-23 04:45:47 +02:00
#include "global.h"
2018-09-11 03:04:03 +02:00
#include "event_data.h"
#include "event_object_movement.h"
2018-12-27 23:30:47 +01:00
#include "field_camera.h"
#include "field_screen_effect.h"
#include "field_specials.h"
#include "fieldmap.h"
2018-09-11 03:04:03 +02:00
#include "main.h"
2018-12-27 23:30:47 +01:00
#include "overworld.h"
2017-09-23 04:45:47 +02:00
#include "palette.h"
#include "script.h"
2018-09-11 03:04:03 +02:00
#include "script_movement.h"
#include "sound.h"
#include "sprite.h"
#include "task.h"
2019-05-25 21:26:29 +02:00
#include "constants/event_objects.h"
2019-11-21 20:03:35 +01:00
#include "constants/event_object_movement.h"
2019-11-08 09:37:46 +01:00
#include "constants/field_specials.h"
2018-09-11 03:04:03 +02:00
#include "constants/songs.h"
#include "constants/metatile_labels.h"
2017-09-23 04:45:47 +02:00
2022-06-01 18:41:57 +02:00
// Most of the boxes in the moving truck are map tiles, with the
// exception of three boxes that are map events that jostle around
// while the truck is driving. In addition, their sprite's placement
// is slightly offset to make them look less perfectly stacked.
// Box 1 (LOCALID_TRUCK_BOX_TOP)
#define BOX1_X_OFFSET 3
#define BOX1_Y_OFFSET 3
// Box 2 (LOCALID_TRUCK_BOX_BOTTOM_L)
#define BOX2_X_OFFSET 0
#define BOX2_Y_OFFSET -3
// Box 3 (LOCALID_TRUCK_BOX_BOTTOM_R)
#define BOX3_X_OFFSET -3
#define BOX3_Y_OFFSET 0
2017-09-23 04:45:47 +02:00
// porthole states
enum
{
INIT_PORTHOLE,
IDLE_CHECK,
EXECUTE_MOVEMENT,
EXIT_PORTHOLE,
};
2022-06-01 18:41:57 +02:00
static const s8 sTruckCamera_HorizontalTable[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, -1, -1, -1, 0};
2019-11-08 09:37:46 +01:00
static const u8 sSSTidalSailEastMovementScript[] =
2019-11-08 09:37:46 +01:00
{
MOVEMENT_ACTION_WALK_FAST_RIGHT,
2019-11-08 09:37:46 +01:00
MOVEMENT_ACTION_STEP_END
};
static const u8 sSSTidalSailWestMovementScript[] =
2019-11-08 09:37:46 +01:00
{
MOVEMENT_ACTION_WALK_FAST_LEFT,
2019-11-08 09:37:46 +01:00
MOVEMENT_ACTION_STEP_END
};
2017-09-23 04:45:47 +02:00
2018-12-27 23:30:47 +01:00
static void Task_Truck3(u8);
2017-09-23 04:45:47 +02:00
2022-06-01 18:41:57 +02:00
static s16 GetTruckCameraBobbingY(int time)
2017-09-23 04:45:47 +02:00
{
2022-06-01 18:41:57 +02:00
if (!(time % 120))
2017-09-23 04:45:47 +02:00
return -1;
2022-06-01 18:41:57 +02:00
else if ((time % 10) <= 4)
2017-09-23 04:45:47 +02:00
return 1;
return 0;
}
2022-06-01 18:41:57 +02:00
// Determines the frequency that the truck boxes bounce at.
// The return value of this function is multiplied and added
// to the boxes resting y offset, the result of which is that
// when it returns 0 they remain vertically still and when it
// returns -1 they jump upward.
// Box 1 has 30 added to the time so it jumps earlier, and
// box 2 has the return value multiplied by less, so it doesn't
// jump as high.
static s16 GetTruckBoxYMovement(int time)
2017-09-23 04:45:47 +02:00
{
2022-06-01 18:41:57 +02:00
if (!((time + 120) % 180))
2017-09-23 04:45:47 +02:00
return -1;
return 0;
}
2022-06-01 18:41:57 +02:00
#define tTimer data[0]
static void Task_Truck1(u8 taskId)
2017-09-23 04:45:47 +02:00
{
s16 *data = gTasks[taskId].data;
2018-08-16 03:50:56 +02:00
s16 cameraXpan = 0, cameraYpan = 0;
2022-06-01 18:41:57 +02:00
s16 yBox1, yBox2, yBox3;
2017-09-23 04:45:47 +02:00
2022-06-01 18:41:57 +02:00
yBox1 = GetTruckBoxYMovement(tTimer + 30) * 4;
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_TOP, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX1_X_OFFSET - cameraXpan, BOX1_Y_OFFSET + yBox1);
yBox2 = GetTruckBoxYMovement(tTimer) * 2;
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_L, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX2_X_OFFSET - cameraXpan, BOX2_Y_OFFSET + yBox2);
yBox3 = GetTruckBoxYMovement(tTimer) * 4;
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_R, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX3_X_OFFSET - cameraXpan, BOX3_Y_OFFSET + yBox3);
2017-09-23 04:45:47 +02:00
2022-06-01 18:41:57 +02:00
// Arbitrary timer limit that won't be reached
if (++tTimer == 30000)
tTimer = 0;
2017-09-23 04:45:47 +02:00
2022-06-01 18:41:57 +02:00
cameraYpan = GetTruckCameraBobbingY(tTimer);
2018-08-16 03:50:56 +02:00
SetCameraPanning(cameraXpan, cameraYpan);
2017-09-23 04:45:47 +02:00
}
2022-06-01 18:41:57 +02:00
#undef tTimer
#define tTimerHorizontal data[0]
#define tMoveStep data[1]
#define tTimerVertical data[2]
static void Task_Truck2(u8 taskId)
2017-09-23 04:45:47 +02:00
{
s16 *data = gTasks[taskId].data;
2022-06-01 18:41:57 +02:00
s16 cameraYpan, cameraXpan;
s16 yBox1, yBox2, yBox3;
2017-09-23 04:45:47 +02:00
2022-06-01 18:41:57 +02:00
tTimerHorizontal++;
tTimerVertical++;
2017-09-23 04:45:47 +02:00
2022-06-01 18:41:57 +02:00
if (tTimerHorizontal > 5)
2017-09-23 04:45:47 +02:00
{
2022-06-01 18:41:57 +02:00
tTimerHorizontal = 0;
tMoveStep++;
2017-09-23 04:45:47 +02:00
}
2022-06-01 18:41:57 +02:00
if ((u16)tMoveStep == ARRAY_COUNT(sTruckCamera_HorizontalTable))
2017-09-23 04:45:47 +02:00
{
2022-06-01 18:41:57 +02:00
// Never reached, the task function is changed below before finishing the table
2017-09-23 04:45:47 +02:00
DestroyTask(taskId);
}
else
{
2022-06-01 18:41:57 +02:00
if (sTruckCamera_HorizontalTable[tMoveStep] == 2)
2017-09-23 04:45:47 +02:00
gTasks[taskId].func = Task_Truck3;
2022-06-01 18:41:57 +02:00
cameraXpan = sTruckCamera_HorizontalTable[tMoveStep];
cameraYpan = GetTruckCameraBobbingY(tTimerVertical);
2017-09-23 04:45:47 +02:00
SetCameraPanning(cameraXpan, cameraYpan);
2022-06-01 18:41:57 +02:00
yBox1 = GetTruckBoxYMovement(tTimerVertical + 30) * 4;
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_TOP, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX1_X_OFFSET - cameraXpan, BOX1_Y_OFFSET + yBox1);
yBox2 = GetTruckBoxYMovement(tTimerVertical) * 2;
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_L, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX2_X_OFFSET - cameraXpan, BOX2_Y_OFFSET + yBox2);
yBox3 = GetTruckBoxYMovement(tTimerVertical) * 4;
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_R, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX3_X_OFFSET - cameraXpan, BOX3_Y_OFFSET + yBox3);
2017-09-23 04:45:47 +02:00
}
}
2018-12-27 23:30:47 +01:00
static void Task_Truck3(u8 taskId)
2017-09-23 04:45:47 +02:00
{
s16 *data = gTasks[taskId].data;
2022-06-01 18:41:57 +02:00
s16 cameraXpan, cameraYpan;
2017-09-23 04:45:47 +02:00
2022-06-01 18:41:57 +02:00
tTimerHorizontal++;
2017-09-23 04:45:47 +02:00
2022-06-01 18:41:57 +02:00
if (tTimerHorizontal > 5)
2017-09-23 04:45:47 +02:00
{
2022-06-01 18:41:57 +02:00
tTimerHorizontal = 0;
tMoveStep++;
2017-09-23 04:45:47 +02:00
}
2022-06-01 18:41:57 +02:00
if ((u16)tMoveStep == ARRAY_COUNT(sTruckCamera_HorizontalTable))
2017-09-23 04:45:47 +02:00
{
DestroyTask(taskId);
}
else
{
2022-06-01 18:41:57 +02:00
cameraXpan = sTruckCamera_HorizontalTable[tMoveStep];
2017-09-23 04:45:47 +02:00
cameraYpan = 0;
SetCameraPanning(cameraXpan, cameraYpan);
2022-06-01 18:41:57 +02:00
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_TOP, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX1_X_OFFSET - cameraXpan, BOX1_Y_OFFSET + cameraYpan);
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_L, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX2_X_OFFSET - cameraXpan, BOX2_Y_OFFSET + cameraYpan);
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_R, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX3_X_OFFSET - cameraXpan, BOX3_Y_OFFSET + cameraYpan);
2017-09-23 04:45:47 +02:00
}
}
2022-06-01 18:41:57 +02:00
#undef tTimerHorizontal
#undef tMoveStep
#undef tTimerVertical
#define tState data[0]
#define tTimer data[1]
#define tTaskId1 data[2]
#define tTaskId2 data[3]
static void Task_HandleTruckSequence(u8 taskId)
2017-09-23 04:45:47 +02:00
{
s16 *data = gTasks[taskId].data;
2022-06-01 18:41:57 +02:00
switch (tState)
2017-09-23 04:45:47 +02:00
{
case 0:
2022-06-01 18:41:57 +02:00
tTimer++;
if (tTimer == 90)
2017-09-23 04:45:47 +02:00
{
SetCameraPanningCallback(NULL);
2022-06-01 18:41:57 +02:00
tTimer = 0;
tTaskId1 = CreateTask(Task_Truck1, 0xA);
tState = 1;
2020-08-21 00:02:00 +02:00
PlaySE(SE_TRUCK_MOVE);
2017-09-23 04:45:47 +02:00
}
break;
case 1:
2022-06-01 18:41:57 +02:00
tTimer++;
if (tTimer == 150)
2017-09-23 04:45:47 +02:00
{
2019-12-17 09:24:44 +01:00
FadeInFromBlack();
2022-06-01 18:41:57 +02:00
tTimer = 0;
tState = 2;
2017-09-23 04:45:47 +02:00
}
break;
case 2:
2022-06-01 18:41:57 +02:00
tTimer++;
if (!gPaletteFade.active && tTimer > 300)
2017-09-23 04:45:47 +02:00
{
2022-06-01 18:41:57 +02:00
tTimer = 0;
DestroyTask(tTaskId1);
tTaskId2 = CreateTask(Task_Truck2, 0xA);
tState = 3;
2020-08-21 00:02:00 +02:00
PlaySE(SE_TRUCK_STOP);
2017-09-23 04:45:47 +02:00
}
break;
case 3:
2022-06-01 18:41:57 +02:00
if (!gTasks[tTaskId2].isActive)
2017-09-23 04:45:47 +02:00
{
2022-06-01 18:41:57 +02:00
// Task_Truck2 / Task_Truck3 has finished
2017-09-23 04:45:47 +02:00
InstallCameraPanAheadCallback();
2022-06-01 18:41:57 +02:00
tTimer = 0;
tState = 4;
2017-09-23 04:45:47 +02:00
}
break;
case 4:
2022-06-01 18:41:57 +02:00
tTimer++;
if (tTimer == 90)
2017-09-23 04:45:47 +02:00
{
2020-08-21 00:02:00 +02:00
PlaySE(SE_TRUCK_UNLOAD);
2022-06-01 18:41:57 +02:00
tTimer = 0;
tState = 5;
2017-09-23 04:45:47 +02:00
}
break;
case 5:
2022-06-01 18:41:57 +02:00
tTimer++;
if (tTimer == 120)
2017-09-23 04:45:47 +02:00
{
2021-10-09 18:12:18 +02:00
MapGridSetMetatileIdAt(4 + MAP_OFFSET, 1 + MAP_OFFSET, METATILE_InsideOfTruck_ExitLight_Top);
MapGridSetMetatileIdAt(4 + MAP_OFFSET, 2 + MAP_OFFSET, METATILE_InsideOfTruck_ExitLight_Mid);
MapGridSetMetatileIdAt(4 + MAP_OFFSET, 3 + MAP_OFFSET, METATILE_InsideOfTruck_ExitLight_Bottom);
2017-09-23 04:45:47 +02:00
DrawWholeMapView();
2020-08-21 00:02:00 +02:00
PlaySE(SE_TRUCK_DOOR);
2017-09-23 04:45:47 +02:00
DestroyTask(taskId);
UnlockPlayerFieldControls();
2017-09-23 04:45:47 +02:00
}
break;
}
}
void ExecuteTruckSequence(void)
{
2021-10-09 18:12:18 +02:00
MapGridSetMetatileIdAt(4 + MAP_OFFSET, 1 + MAP_OFFSET, METATILE_InsideOfTruck_DoorClosedFloor_Top);
MapGridSetMetatileIdAt(4 + MAP_OFFSET, 2 + MAP_OFFSET, METATILE_InsideOfTruck_DoorClosedFloor_Mid);
MapGridSetMetatileIdAt(4 + MAP_OFFSET, 3 + MAP_OFFSET, METATILE_InsideOfTruck_DoorClosedFloor_Bottom);
2017-09-23 04:45:47 +02:00
DrawWholeMapView();
LockPlayerFieldControls();
2023-05-23 19:16:18 +02:00
CpuFastFill(0, gPlttBufferFaded, PLTT_SIZE);
2017-09-23 04:45:47 +02:00
CreateTask(Task_HandleTruckSequence, 0xA);
}
void EndTruckSequence(u8 taskId)
{
if (!FuncIsActiveTask(Task_HandleTruckSequence))
{
2022-06-01 18:41:57 +02:00
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_TOP, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX1_X_OFFSET, BOX1_Y_OFFSET);
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_L, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX2_X_OFFSET, BOX2_Y_OFFSET);
SetObjectEventSpritePosByLocalIdAndMap(LOCALID_TRUCK_BOX_BOTTOM_R, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, BOX3_X_OFFSET, BOX3_Y_OFFSET);
2017-09-23 04:45:47 +02:00
}
}
2019-12-17 09:24:44 +01:00
bool8 TrySetPortholeWarpDestination(void)
2017-09-23 04:45:47 +02:00
{
s8 mapGroup, mapNum;
s16 x, y;
2019-12-17 09:24:44 +01:00
if (GetSSTidalLocation(&mapGroup, &mapNum, &x, &y) != SS_TIDAL_LOCATION_CURRENTS)
2017-09-23 04:45:47 +02:00
{
return FALSE;
}
else
{
2022-06-01 18:41:57 +02:00
SetWarpDestination(mapGroup, mapNum, WARP_ID_NONE, x, y);
2017-09-23 04:45:47 +02:00
return TRUE;
}
}
void Task_HandlePorthole(u8 taskId)
{
s16 *data = gTasks[taskId].data;
2019-11-08 09:37:46 +01:00
u16 *cruiseState = GetVarPointer(VAR_SS_TIDAL_STATE);
2017-09-23 04:45:47 +02:00
struct WarpData *location = &gSaveBlock1Ptr->location;
switch (data[0])
{
case INIT_PORTHOLE: // finish fading before making porthole finish.
if (!gPaletteFade.active)
{
data[1] = 0;
data[0] = EXECUTE_MOVEMENT; // execute movement before checking if should be exited. strange?
}
break;
2019-11-08 09:37:46 +01:00
case IDLE_CHECK:
2020-09-05 03:11:55 +02:00
if (JOY_NEW(A_BUTTON))
2017-09-23 04:45:47 +02:00
data[1] = 1;
if (!ScriptMovement_IsObjectMovementFinished(OBJ_EVENT_ID_PLAYER, location->mapNum, location->mapGroup))
2017-09-23 04:45:47 +02:00
return;
if (CountSSTidalStep(1) == TRUE)
{
2019-11-08 09:37:46 +01:00
if (*cruiseState == SS_TIDAL_DEPART_SLATEPORT)
*cruiseState = SS_TIDAL_EXIT_CURRENTS_RIGHT;
2017-09-23 04:45:47 +02:00
else
2019-11-08 09:37:46 +01:00
*cruiseState = SS_TIDAL_EXIT_CURRENTS_LEFT;
data[0] = EXIT_PORTHOLE;
2017-09-23 04:45:47 +02:00
return;
}
2019-11-08 09:37:46 +01:00
data[0] = EXECUTE_MOVEMENT;
//fallthrough
case EXECUTE_MOVEMENT:
2017-09-23 04:45:47 +02:00
if (data[1])
{
2019-11-08 09:37:46 +01:00
data[0] = EXIT_PORTHOLE;
2017-09-23 04:45:47 +02:00
return;
}
2019-11-08 09:37:46 +01:00
if (*cruiseState == SS_TIDAL_DEPART_SLATEPORT)
2017-09-23 04:45:47 +02:00
{
ScriptMovement_StartObjectMovementScript(OBJ_EVENT_ID_PLAYER, location->mapNum, location->mapGroup, sSSTidalSailEastMovementScript);
2019-11-08 09:37:46 +01:00
data[0] = IDLE_CHECK;
2017-09-23 04:45:47 +02:00
}
else
{
ScriptMovement_StartObjectMovementScript(OBJ_EVENT_ID_PLAYER, location->mapNum, location->mapGroup, sSSTidalSailWestMovementScript);
2019-11-08 09:37:46 +01:00
data[0] = IDLE_CHECK;
2017-09-23 04:45:47 +02:00
}
break;
2019-11-08 09:37:46 +01:00
case EXIT_PORTHOLE:
FlagClear(FLAG_DONT_TRANSITION_MUSIC);
2019-03-10 13:10:59 +01:00
FlagClear(FLAG_HIDE_MAP_NAME_POPUP);
2018-12-27 23:30:47 +01:00
SetWarpDestinationToDynamicWarp(0);
2018-12-28 22:11:15 +01:00
DoDiveWarp();
2017-09-23 04:45:47 +02:00
DestroyTask(taskId);
break;
}
}
2019-11-08 09:37:46 +01:00
static void ShowSSTidalWhileSailing(void)
2017-09-23 04:45:47 +02:00
{
u8 spriteId = CreateObjectGraphicsSprite(OBJ_EVENT_GFX_SS_TIDAL, SpriteCallbackDummy, 112, 80, 0);
2017-09-23 04:45:47 +02:00
gSprites[spriteId].coordOffsetEnabled = FALSE;
2019-11-08 09:37:46 +01:00
if (VarGet(VAR_SS_TIDAL_STATE) == SS_TIDAL_DEPART_SLATEPORT)
StartSpriteAnim(&gSprites[spriteId], GetFaceDirectionAnimNum(DIR_EAST));
2017-09-23 04:45:47 +02:00
else
2019-11-08 09:37:46 +01:00
StartSpriteAnim(&gSprites[spriteId], GetFaceDirectionAnimNum(DIR_WEST));
2017-09-23 04:45:47 +02:00
}
2019-12-17 09:24:44 +01:00
void FieldCB_ShowPortholeView(void)
2017-09-23 04:45:47 +02:00
{
2019-11-08 09:37:46 +01:00
ShowSSTidalWhileSailing();
gObjectEvents[gPlayerAvatar.objectEventId].invisible = TRUE;
2019-12-17 09:24:44 +01:00
FadeInFromBlack();
2017-09-23 04:45:47 +02:00
CreateTask(Task_HandlePorthole, 80);
LockPlayerFieldControls();
2017-09-23 04:45:47 +02:00
}
2019-11-08 09:37:46 +01:00
void LookThroughPorthole(void)
2017-09-23 04:45:47 +02:00
{
2017-11-08 22:20:10 +01:00
FlagSet(FLAG_SYS_CRUISE_MODE);
FlagSet(FLAG_DONT_TRANSITION_MUSIC);
2019-03-10 13:10:59 +01:00
FlagSet(FLAG_HIDE_MAP_NAME_POPUP);
SetDynamicWarp(0, gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum, WARP_ID_NONE);
2019-12-17 09:24:44 +01:00
TrySetPortholeWarpDestination();
DoPortholeWarp();
2017-09-23 04:45:47 +02:00
}