pokeemerald/src/cable_car.c

1072 lines
33 KiB
C
Raw Normal View History

2018-12-09 20:41:52 +01:00
#include "global.h"
#include "bg.h"
#include "decompress.h"
#include "event_data.h"
#include "event_object_movement.h"
#include "field_weather.h"
#include "gpu_regs.h"
#include "graphics.h"
#include "malloc.h"
2018-12-09 20:41:52 +01:00
#include "main.h"
#include "menu.h"
#include "overworld.h"
#include "palette.h"
#include "random.h"
#include "scanline_effect.h"
#include "script.h"
#include "sound.h"
#include "sprite.h"
#include "task.h"
2021-10-29 19:37:49 +02:00
#include "constants/event_object_movement.h"
2018-12-09 20:41:52 +01:00
#include "constants/event_objects.h"
#include "constants/rgb.h"
#include "constants/songs.h"
#include "constants/weather.h"
2020-08-28 09:49:15 +02:00
#define GOING_DOWN gSpecialVar_0x8004
#define STATE_END 0xFF
#define TAG_CABLE_CAR 1
#define TAG_DOOR 2
#define TAG_CABLE 3
2018-12-09 20:41:52 +01:00
struct CableCar
{
2020-08-28 09:49:15 +02:00
u8 bgTaskId;
2018-12-09 20:41:52 +01:00
u8 state;
u8 weather;
2020-08-28 09:49:15 +02:00
u16 weatherDelay;
2018-12-09 20:41:52 +01:00
u16 timer;
u8 bg0HorizontalOffset;
u8 bg0VerticalOffset;
2020-08-28 09:49:15 +02:00
u8 unused0[2];
2018-12-09 20:41:52 +01:00
u8 bg1HorizontalOffset;
u8 bg1VerticalOffset;
2020-08-28 09:49:15 +02:00
u8 unused1[6];
2018-12-09 20:41:52 +01:00
u8 bg3HorizontalOffset;
u8 bg3VerticalOffset;
2020-08-28 09:49:15 +02:00
u8 unused2[2];
u8 groundTileIdx;
u8 groundSegmentXStart;
u8 groundSegmentYStart;
u8 groundTilemapOffset;
u8 groundTimer; // Incremented, but does nothing
u8 groundXOffset;
u8 groundYOffset;
u8 groundXBase;
u8 groundYBase;
u16 groundTileBuffer[9][12];
u8 unused3[2];
u16 bgTilemapBuffers[4][BG_SCREEN_SIZE];
u16 *groundTilemap;
u16 *treesTilemap;
u16 *bgMountainsTilemap;
const u16 *pylonHookTilemapEntries;
u8 *pylonStemTilemap;
2018-12-09 20:41:52 +01:00
};
static EWRAM_DATA struct CableCar *sCableCar = NULL;
2020-08-28 09:49:15 +02:00
static EWRAM_DATA u8 sGroundX_Up = 0;
static EWRAM_DATA u8 sGroundY_Up = 0;
2020-09-03 22:17:29 +02:00
static EWRAM_DATA u8 sGroundSegmentY_Up = 0;
2020-08-28 09:49:15 +02:00
static EWRAM_DATA u8 sGroundX_Down = 0;
static EWRAM_DATA u8 sGroundY_Down = 0;
static EWRAM_DATA u8 sGroundSegmentY_Down = 0;
static void CB2_LoadCableCar(void);
static void SetBgRegs(bool8);
static void CreateCableCarSprites(void);
static void InitGroundTilemapData(bool8);
static void Task_CableCar(u8);
static void Task_AnimateBgGoingUp(u8);
static void Task_AnimateBgGoingDown(u8);
static void VBlankCB_CableCar(void);
static void CB2_CableCar(void);
static void AnimateGroundGoingUp(void);
static void AnimateGroundGoingDown(void);
static void SpriteCB_CableCar(struct Sprite *);
static void SpriteCB_Cable(struct Sprite *);
static void DrawNextGroundSegmentGoingUp(void);
static void DrawNextGroundSegmentGoingDown(void);
static const struct BgTemplate sBgTemplates[4] = {
2018-12-09 20:41:52 +01:00
{
.bg = 0,
.charBaseIndex = 0,
.mapBaseIndex = 28,
.screenSize = 0,
.paletteMode = 0,
.priority = 1,
.baseTile = 0
},
{
.bg = 1,
.charBaseIndex = 0,
.mapBaseIndex = 29,
.screenSize = 0,
.paletteMode = 0,
.priority = 2,
.baseTile = 0
},
{
.bg = 2,
.charBaseIndex = 0,
.mapBaseIndex = 30,
.screenSize = 0,
.paletteMode = 0,
.priority = 3,
.baseTile = 0
},
{
.bg = 3,
.charBaseIndex = 0,
.mapBaseIndex = 31,
.screenSize = 0,
.paletteMode = 0,
.priority = 0,
.baseTile = 0
},
};
2020-08-28 09:49:15 +02:00
static const u8 sGround_Tilemap[] = INCBIN_U8("graphics/cable_car/ground.bin.lz");
static const u8 sTrees_Tilemap[] = INCBIN_U8("graphics/cable_car/trees.bin.lz");
static const u8 sBgMountains_Tilemap[] = INCBIN_U8("graphics/cable_car/bg_mountains.bin.lz");
2018-12-09 20:41:52 +01:00
2020-08-28 09:49:15 +02:00
static const u16 sPylonHook_TilemapEntries[] = {
2018-12-09 20:41:52 +01:00
0x3000,
0x3001,
0x3002,
0x3003,
0x3004,
0x3005,
0x3006,
0x3007,
0x3008,
0x3009,
};
2020-08-28 09:49:15 +02:00
static const u8 sPylonStems_Tilemap[] = INCBIN_U8("graphics/cable_car/pylons.bin.lz");
2018-12-09 20:41:52 +01:00
2020-08-28 09:49:15 +02:00
static const struct CompressedSpriteSheet sSpriteSheets[] = {
{ gCableCar_Gfx, 0x800, TAG_CABLE_CAR },
{ gCableCarDoor_Gfx, 0x40, TAG_DOOR },
{ gCableCarCable_Gfx, 0x80, TAG_CABLE },
2018-12-09 20:41:52 +01:00
{ },
};
2020-08-28 09:49:15 +02:00
static const struct SpritePalette sSpritePalettes[] = {
{ gCableCar_Pal, TAG_CABLE_CAR },
2018-12-09 20:41:52 +01:00
{ }
};
2020-08-28 09:49:15 +02:00
static const struct OamData sOam_CableCar =
2019-04-02 00:31:10 +02:00
{
.y = 0,
2018-12-09 20:41:52 +01:00
.affineMode = ST_OAM_AFFINE_DOUBLE,
2019-04-02 00:31:10 +02:00
.objMode = ST_OAM_OBJ_NORMAL,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(64x64),
2019-04-02 00:31:10 +02:00
.x = 0,
.size = SPRITE_SIZE(64x64),
2019-04-02 00:31:10 +02:00
.tileNum = 0,
.priority = 2,
.paletteNum = 0,
2018-12-09 20:41:52 +01:00
};
2020-08-28 09:49:15 +02:00
static const struct OamData sOam_CableCarDoor =
2019-04-02 00:31:10 +02:00
{
.y = 0,
2018-12-09 20:41:52 +01:00
.affineMode = ST_OAM_AFFINE_DOUBLE,
2019-04-02 00:31:10 +02:00
.objMode = ST_OAM_OBJ_NORMAL,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(16x8),
2019-04-02 00:31:10 +02:00
.x = 0,
.size = SPRITE_SIZE(16x8),
2019-04-02 00:31:10 +02:00
.tileNum = 0,
.priority = 2,
.paletteNum = 0,
2018-12-09 20:41:52 +01:00
};
2020-08-28 09:49:15 +02:00
static const struct OamData sOam_Cable =
2019-04-02 00:31:10 +02:00
{
.y = 0,
2018-12-09 20:41:52 +01:00
.affineMode = ST_OAM_AFFINE_DOUBLE,
2019-04-02 00:31:10 +02:00
.objMode = ST_OAM_OBJ_NORMAL,
.bpp = ST_OAM_4BPP,
.shape = SPRITE_SHAPE(16x16),
2019-04-02 00:31:10 +02:00
.x = 0,
.size = SPRITE_SIZE(16x16),
2019-04-02 00:31:10 +02:00
.tileNum = 0,
.priority = 2,
.paletteNum = 0,
2018-12-09 20:41:52 +01:00
};
2020-08-28 09:49:15 +02:00
static const struct SpriteTemplate sSpriteTemplate_CableCar[] =
2018-12-09 20:41:52 +01:00
{
{
2020-08-28 09:49:15 +02:00
.tileTag = TAG_CABLE_CAR,
.paletteTag = TAG_CABLE_CAR,
.oam = &sOam_CableCar,
2018-12-09 20:41:52 +01:00
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
2020-08-28 09:49:15 +02:00
.callback = SpriteCB_CableCar,
2018-12-09 20:41:52 +01:00
},
{
2020-08-28 09:49:15 +02:00
.tileTag = TAG_DOOR,
.paletteTag = TAG_CABLE_CAR,
.oam = &sOam_CableCarDoor,
2018-12-09 20:41:52 +01:00
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
2020-08-28 09:49:15 +02:00
.callback = SpriteCB_CableCar,
2018-12-09 20:41:52 +01:00
},
};
2020-08-28 09:49:15 +02:00
static const struct SpriteTemplate sSpriteTemplate_Cable = {
.tileTag = TAG_CABLE,
.paletteTag = TAG_CABLE_CAR,
.oam = &sOam_Cable,
2018-12-09 20:41:52 +01:00
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
2020-08-28 09:49:15 +02:00
.callback = SpriteCB_Cable,
2018-12-09 20:41:52 +01:00
};
2020-08-28 09:49:15 +02:00
static void Task_LoadCableCar(u8 taskId)
2018-12-09 20:41:52 +01:00
{
if (!gPaletteFade.active)
{
2020-08-28 09:49:15 +02:00
SetMainCallback2(CB2_LoadCableCar);
2018-12-09 20:41:52 +01:00
DestroyTask(taskId);
}
}
void CableCar(void)
{
ScriptContext2_Enable();
2020-08-28 09:49:15 +02:00
CreateTask(Task_LoadCableCar, 1);
2021-02-24 17:01:02 +01:00
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB(0, 0, 0));
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
static void CB2_LoadCableCar(void)
2018-12-09 20:41:52 +01:00
{
u16 imebak;
u8 i = 0;
2019-07-19 02:46:00 +02:00
u32 sizeOut = 0;
2018-12-09 20:41:52 +01:00
switch (gMain.state)
{
case 0:
default:
SetVBlankCallback(NULL);
2020-08-28 09:49:15 +02:00
SetBgRegs(FALSE);
2018-12-09 20:41:52 +01:00
ScanlineEffect_Stop();
DmaFillLarge16(3, 0, (void *)VRAM, VRAM_SIZE, 0x1000);
DmaFill32Defvars(3, 0, (void *)OAM, OAM_SIZE);
DmaFill16Defvars(3, 0, (void *)PLTT, PLTT_SIZE);
sCableCar = AllocZeroed(sizeof(*sCableCar));
gMain.state++;
break;
case 1:
ResetSpriteData();
ResetTasks();
FreeAllSpritePalettes();
ResetPaletteFade();
2020-05-14 10:37:09 +02:00
ResetTempTileDataBuffers();
2018-12-09 20:41:52 +01:00
StartWeather();
2020-08-28 09:49:15 +02:00
for (i = 0; i < NUM_ASH_SPRITES; i++)
2018-12-09 20:41:52 +01:00
gWeatherPtr->sprites.s2.ashSprites[i] = NULL;
InitMapMusic();
ResetMapMusic();
ResetBgsAndClearDma3BusyFlags(0);
2020-08-28 09:49:15 +02:00
InitBgsFromTemplates(0, sBgTemplates, ARRAY_COUNT(sBgTemplates));
2018-12-09 20:41:52 +01:00
SetBgTilemapBuffer(0, sCableCar->bgTilemapBuffers[0]);
SetBgTilemapBuffer(1, sCableCar->bgTilemapBuffers[1]);
SetBgTilemapBuffer(2, sCableCar->bgTilemapBuffers[2]);
SetBgTilemapBuffer(3, sCableCar->bgTilemapBuffers[3]);
gSpriteCoordOffsetX = gSpriteCoordOffsetY = 0;
gMain.state++;
break;
case 2:
2020-08-28 09:49:15 +02:00
for (i = 0; i < ARRAY_COUNT(sSpriteSheets) - 1; i++)
LoadCompressedSpriteSheet(&sSpriteSheets[i]);
LoadSpritePalettes(sSpritePalettes);
sCableCar->groundTilemap = malloc_and_decompress(sGround_Tilemap, &sizeOut);
sCableCar->treesTilemap = malloc_and_decompress(sTrees_Tilemap, &sizeOut);
sCableCar->bgMountainsTilemap = malloc_and_decompress(sBgMountains_Tilemap, &sizeOut);
sCableCar->pylonStemTilemap = malloc_and_decompress(sPylonStems_Tilemap, &sizeOut);
sCableCar->pylonHookTilemapEntries = sPylonHook_TilemapEntries;
DecompressAndCopyTileDataToVram(0, gCableCarBg_Gfx, 0, 0, 0);
2018-12-09 20:41:52 +01:00
gMain.state++;
break;
case 3:
2020-05-14 10:37:09 +02:00
if (!FreeTempTileDataBuffersIfPossible())
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
LoadPalette(gCableCarBg_Pal, 0, 0x80);
2018-12-09 20:41:52 +01:00
gMain.state++;
}
break;
case 4:
2020-08-28 09:49:15 +02:00
CreateCableCarSprites();
2018-12-09 20:41:52 +01:00
RunTasks();
gMain.state++;
break;
case 5:
2019-12-02 01:19:47 +01:00
if (sCableCar->weather == WEATHER_VOLCANIC_ASH)
2018-12-09 20:41:52 +01:00
{
gMain.state++;
}
else if (gWeatherPtr->sprites.s2.ashSprites[0])
{
2020-08-28 09:49:15 +02:00
for (i = 0; i < NUM_ASH_SPRITES; i++)
2018-12-09 20:41:52 +01:00
{
if (gWeatherPtr->sprites.s2.ashSprites[i])
gWeatherPtr->sprites.s2.ashSprites[i]->oam.priority = 0;
}
gMain.state++;
}
break;
case 6:
2020-08-28 09:49:15 +02:00
CopyToBgTilemapBufferRect_ChangePalette(1, sCableCar->treesTilemap, 0, 17, 32, 15, 17);
CopyToBgTilemapBufferRect_ChangePalette(2, sCableCar->bgMountainsTilemap, 0, 0, 30, 20, 17);
2018-12-09 20:41:52 +01:00
CopyToBgTilemapBufferRect_ChangePalette(3, sCableCar->pylonHookTilemapEntries, 0, 0, 5, 2, 17);
CopyToBgTilemapBufferRect_ChangePalette(3, sCableCar->pylonStemTilemap, 0, 2, 2, 20, 17);
gMain.state++;
break;
case 7:
2020-08-28 09:49:15 +02:00
InitGroundTilemapData(GOING_DOWN);
CopyToBgTilemapBufferRect_ChangePalette(0, sCableCar->groundTilemap + 0x48, 0, 14, 12, 3, 17);
CopyToBgTilemapBufferRect_ChangePalette(0, sCableCar->groundTilemap + 0x6C, 12, 17, 12, 3, 17);
CopyToBgTilemapBufferRect_ChangePalette(0, sCableCar->groundTilemap + 0x90, 24, 20, 12, 3, 17);
CopyToBgTilemapBufferRect_ChangePalette(0, sCableCar->groundTilemap + 0x0, 0, 17, 12, 3, 17);
CopyToBgTilemapBufferRect_ChangePalette(0, sCableCar->groundTilemap + 0x24, 0, 20, 12, 3, 17);
CopyToBgTilemapBufferRect_ChangePalette(0, sCableCar->groundTilemap + 0x0, 12, 20, 12, 3, 17);
CopyToBgTilemapBufferRect_ChangePalette(0, sCableCar->groundTilemap + 0x24, 12, 23, 12, 3, 17);
CopyToBgTilemapBufferRect_ChangePalette(0, sCableCar->groundTilemap + 0x0, 24, 23, 12, 3, 17);
2018-12-09 20:41:52 +01:00
gMain.state++;
break;
case 8:
2021-02-24 17:01:02 +01:00
BeginNormalPaletteFade(PALETTES_ALL, 3, 16, 0, RGB(0, 0, 0));
2020-08-21 00:02:00 +02:00
FadeInNewBGM(MUS_CABLE_CAR, 1);
2020-08-28 09:49:15 +02:00
SetBgRegs(TRUE);
2018-12-09 20:41:52 +01:00
gMain.state++;
break;
case 9:
imebak = REG_IME;
REG_IME = 0;
REG_IE |= INTR_FLAG_VBLANK;
REG_IME = imebak;
2020-08-28 09:49:15 +02:00
SetVBlankCallback(VBlankCB_CableCar);
SetMainCallback2(CB2_CableCar);
CreateTask(Task_CableCar, 0);
if (!GOING_DOWN)
sCableCar->bgTaskId = CreateTask(Task_AnimateBgGoingUp, 1);
2018-12-09 20:41:52 +01:00
else
2020-08-28 09:49:15 +02:00
sCableCar->bgTaskId = CreateTask(Task_AnimateBgGoingDown, 1);
2018-12-09 20:41:52 +01:00
break;
}
}
2020-08-28 09:49:15 +02:00
static void CB2_CableCar(void)
2018-12-09 20:41:52 +01:00
{
RunTasks();
AnimateSprites();
BuildOamBuffer();
UpdatePaletteFade();
MapMusicMain();
}
2020-08-28 09:49:15 +02:00
static void CB2_EndCableCar(void)
2018-12-09 20:41:52 +01:00
{
u8 i = 0;
2018-12-20 22:53:08 +01:00
2018-12-09 20:41:52 +01:00
HideBg(0);
HideBg(1);
HideBg(2);
HideBg(3);
2020-08-28 09:49:15 +02:00
SetBgRegs(FALSE);
2018-12-09 20:41:52 +01:00
gSpriteCoordOffsetX = 0;
SetCurrentAndNextWeatherNoDelay(WEATHER_NONE);
2020-08-28 09:49:15 +02:00
for (i = 0; i < NUM_ASH_SPRITES; i++)
2018-12-09 20:41:52 +01:00
gWeatherPtr->sprites.s2.ashSprites[i] = NULL;
2018-12-20 22:53:08 +01:00
2018-12-09 20:41:52 +01:00
ResetTasks();
ResetSpriteData();
ResetPaletteFade();
UnsetBgTilemapBuffer(0);
UnsetBgTilemapBuffer(1);
UnsetBgTilemapBuffer(2);
UnsetBgTilemapBuffer(3);
ResetBgsAndClearDma3BusyFlags(0);
sCableCar->pylonHookTilemapEntries = NULL;
FREE_AND_SET_NULL(sCableCar->pylonStemTilemap);
2020-08-28 09:49:15 +02:00
FREE_AND_SET_NULL(sCableCar->bgMountainsTilemap);
FREE_AND_SET_NULL(sCableCar->treesTilemap);
FREE_AND_SET_NULL(sCableCar->groundTilemap);
2018-12-09 20:41:52 +01:00
FREE_AND_SET_NULL(sCableCar);
DmaFillLarge16(3, 0, (void *)VRAM, VRAM_SIZE, 0x1000);
DmaFill32Defvars(3, 0, (void *)OAM, OAM_SIZE);
DmaFill16Defvars(3, 0, (void *)PLTT, PLTT_SIZE);
WarpIntoMap();
gFieldCallback = NULL;
SetMainCallback2(CB2_LoadMap);
}
2020-08-28 09:49:15 +02:00
static void Task_CableCar(u8 taskId)
2018-12-09 20:41:52 +01:00
{
u8 i = 0;
sCableCar->timer++;
switch (sCableCar->state)
{
case 0:
2020-08-28 09:49:15 +02:00
// Wait to change weather
if (sCableCar->timer == sCableCar->weatherDelay)
2018-12-09 20:41:52 +01:00
{
SetNextWeather(sCableCar->weather);
2018-12-09 20:41:52 +01:00
sCableCar->state = 1;
}
break;
case 1:
2020-08-28 09:49:15 +02:00
// Update ash sprites
2018-12-09 20:41:52 +01:00
switch (sCableCar->weather)
{
2019-12-02 01:19:47 +01:00
case WEATHER_VOLCANIC_ASH:
2018-12-09 20:41:52 +01:00
if (gWeatherPtr->sprites.s2.ashSprites[0] != NULL && gWeatherPtr->sprites.s2.ashSprites[0]->oam.priority != 0)
{
for (; i < NUM_ASH_SPRITES; i++)
2018-12-09 20:41:52 +01:00
{
if (gWeatherPtr->sprites.s2.ashSprites[i])
2018-12-09 20:41:52 +01:00
gWeatherPtr->sprites.s2.ashSprites[i]->oam.priority = 0;
}
2018-12-09 20:41:52 +01:00
sCableCar->state = 2;
}
break;
case WEATHER_SUNNY:
if (gWeatherPtr->currWeather == WEATHER_SUNNY)
{
sCableCar->state = 2;
}
2020-08-28 09:49:15 +02:00
else if (sCableCar->timer >= sCableCar->weatherDelay + 8)
2018-12-09 20:41:52 +01:00
{
for (; i < NUM_ASH_SPRITES; i++)
2018-12-09 20:41:52 +01:00
{
if (gWeatherPtr->sprites.s2.ashSprites[i])
gWeatherPtr->sprites.s2.ashSprites[i]->invisible ^= 1;
2018-12-09 20:41:52 +01:00
}
}
break;
}
break;
case 2:
2020-08-28 09:49:15 +02:00
// Wait to fade out
2018-12-09 20:41:52 +01:00
if (sCableCar->timer == 570)
{
sCableCar->state = 3;
2021-02-24 17:01:02 +01:00
BeginNormalPaletteFade(PALETTES_ALL, 3, 0, 16, RGB(0, 0, 0));
2018-12-09 20:41:52 +01:00
FadeOutBGM(4);
}
break;
case 3:
2020-08-28 09:49:15 +02:00
// Wait for fade out
2018-12-09 20:41:52 +01:00
if (!gPaletteFade.active)
2020-08-28 09:49:15 +02:00
sCableCar->state = STATE_END;
2018-12-09 20:41:52 +01:00
break;
2020-08-28 09:49:15 +02:00
case STATE_END:
2018-12-09 20:41:52 +01:00
SetVBlankCallback(NULL);
DestroyTask(taskId);
2020-08-28 09:49:15 +02:00
DestroyTask(sCableCar->bgTaskId);
SetMainCallback2(CB2_EndCableCar);
2018-12-09 20:41:52 +01:00
break;
}
}
2020-08-28 09:49:15 +02:00
static void Task_AnimateBgGoingUp(u8 taskId)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
if (sCableCar->state != STATE_END)
2018-12-09 20:41:52 +01:00
{
sCableCar->bg3HorizontalOffset--;
if ((sCableCar->timer % 2) == 0)
sCableCar->bg3VerticalOffset--;
if ((sCableCar->timer % 8) == 0)
{
sCableCar->bg1HorizontalOffset--;
sCableCar->bg1VerticalOffset--;
}
switch (sCableCar->bg3HorizontalOffset)
{
case 175:
FillBgTilemapBufferRect(3, 0, 0, 22, 2, 10, 17);
break;
case 40:
FillBgTilemapBufferRect(3, 0, 3, 0, 2, 2, 17);
break;
case 32:
FillBgTilemapBufferRect(3, 0, 2, 0, 1, 2, 17);
break;
case 16:
CopyToBgTilemapBufferRect_ChangePalette(3, sCableCar->pylonHookTilemapEntries, 0, 0, 5, 2, 17);
CopyToBgTilemapBufferRect_ChangePalette(3, sCableCar->pylonStemTilemap, 0, 2, 2, 30, 17);
sCableCar->bg3VerticalOffset = 64;
break;
}
}
2020-08-28 09:49:15 +02:00
AnimateGroundGoingUp();
2018-12-09 20:41:52 +01:00
gSpriteCoordOffsetX = (gSpriteCoordOffsetX + 1) % 128;
}
2020-08-28 09:49:15 +02:00
static void Task_AnimateBgGoingDown(u8 taskId)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
if (sCableCar->state != STATE_END)
2018-12-09 20:41:52 +01:00
{
sCableCar->bg3HorizontalOffset++;
if ((sCableCar->timer % 2) == 0)
sCableCar->bg3VerticalOffset++;
if ((sCableCar->timer % 8) == 0)
{
sCableCar->bg1HorizontalOffset++;
sCableCar->bg1VerticalOffset++;
}
switch (sCableCar->bg3HorizontalOffset)
{
case 176:
CopyToBgTilemapBufferRect_ChangePalette(3, sCableCar->pylonStemTilemap, 0, 2, 2, 30, 17);
break;
case 16:
FillBgTilemapBufferRect(3, 0, 2, 0, 3, 2, 17);
FillBgTilemapBufferRect(3, 0, 0, 22, 2, 10, 17);
sCableCar->bg3VerticalOffset = 192;
break;
case 32:
FillBgTilemapBufferRect(3, sCableCar->pylonHookTilemapEntries[2], 2, 0, 1, 1, 17);
FillBgTilemapBufferRect(3, sCableCar->pylonHookTilemapEntries[3], 3, 0, 1, 1, 17);
FillBgTilemapBufferRect(3, sCableCar->pylonHookTilemapEntries[7], 2, 1, 1, 1, 17);
FillBgTilemapBufferRect(3, sCableCar->pylonHookTilemapEntries[8], 3, 1, 1, 1, 17);
break;
case 40:
FillBgTilemapBufferRect(3, sCableCar->pylonHookTilemapEntries[4], 4, 0, 1, 1, 17);
FillBgTilemapBufferRect(3, sCableCar->pylonHookTilemapEntries[9], 4, 1, 1, 1, 17);
break;
}
}
2020-08-28 09:49:15 +02:00
AnimateGroundGoingDown();
if (sCableCar->timer < sCableCar->weatherDelay)
2018-12-09 20:41:52 +01:00
gSpriteCoordOffsetX = (gSpriteCoordOffsetX + 247) % 248;
else
gWeatherPtr->ashBaseSpritesX = (gWeatherPtr->ashBaseSpritesX + 247) % 248;
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
static void VBlankCB_CableCar(void)
2018-12-09 20:41:52 +01:00
{
CopyBgTilemapBufferToVram(0);
CopyBgTilemapBufferToVram(3);
SetGpuReg(REG_OFFSET_BG3HOFS, sCableCar->bg3HorizontalOffset);
SetGpuReg(REG_OFFSET_BG3VOFS, sCableCar->bg3VerticalOffset);
SetGpuReg(REG_OFFSET_BG1HOFS, sCableCar->bg1HorizontalOffset);
SetGpuReg(REG_OFFSET_BG1VOFS, sCableCar->bg1VerticalOffset);
SetGpuReg(REG_OFFSET_BG0HOFS, sCableCar->bg0HorizontalOffset);
SetGpuReg(REG_OFFSET_BG0VOFS, sCableCar->bg0VerticalOffset);
LoadOam();
ProcessSpriteCopyRequests();
TransferPlttBuffer();
}
2020-08-28 09:49:15 +02:00
static void SpriteCB_Cable(struct Sprite *sprite)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
#define sXPos data[0]
#define sYPos data[1]
static void SpriteCB_CableCar(struct Sprite *sprite)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
if (sCableCar->state != STATE_END)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
if (!GOING_DOWN)
2018-12-09 20:41:52 +01:00
{
2021-07-07 15:11:52 +02:00
sprite->x = sprite->sXPos - (u8)(0.14f * S16TOPOSFLOAT(sCableCar->timer));
sprite->y = sprite->sYPos - (u8)(0.067f * S16TOPOSFLOAT(sCableCar->timer));
2018-12-09 20:41:52 +01:00
}
else
{
2021-07-07 15:11:52 +02:00
sprite->x = sprite->sXPos + (u8)(0.14f * S16TOPOSFLOAT(sCableCar->timer));
sprite->y = sprite->sYPos + (u8)(0.067f * S16TOPOSFLOAT(sCableCar->timer));
2018-12-09 20:41:52 +01:00
}
}
}
2020-08-28 09:49:15 +02:00
#define sState data[2]
#define sTimer data[3]
static void SpriteCB_Player(struct Sprite *sprite)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
if (sCableCar->state != STATE_END)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
// Move along with cable car
if (!GOING_DOWN)
2018-12-09 20:41:52 +01:00
{
2021-07-07 15:11:52 +02:00
sprite->x = sprite->sXPos - (u8)(0.14f * S16TOPOSFLOAT(sCableCar->timer));
sprite->y = sprite->sYPos - (u8)(0.067f * S16TOPOSFLOAT(sCableCar->timer));
2018-12-09 20:41:52 +01:00
}
else
{
2021-07-07 15:11:52 +02:00
sprite->x = sprite->sXPos + (u8)(0.14f * S16TOPOSFLOAT(sCableCar->timer));
sprite->y = sprite->sYPos + (u8)(0.067f * S16TOPOSFLOAT(sCableCar->timer));
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
// Bounce up and down
switch (sprite->sState)
2018-12-09 20:41:52 +01:00
{
case 0:
2021-07-07 15:11:52 +02:00
sprite->y2 = 17;
2020-08-28 09:49:15 +02:00
if (sprite->sTimer++ > 9)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
sprite->sTimer = 0;
sprite->sState++;
2018-12-09 20:41:52 +01:00
}
break;
default:
2021-07-07 15:11:52 +02:00
sprite->y2 = 16;
2020-08-28 09:49:15 +02:00
if (sprite->sTimer++ > 9)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
sprite->sTimer = 0;
sprite->sState = 0;
2018-12-09 20:41:52 +01:00
}
break;
}
}
}
2020-08-28 09:49:15 +02:00
#undef sState
#undef sTimer
#define sTimer data[0]
#define sSameDir data[1] // Whether or not the hiker is headed the same dir as the Cable Car
#define sDelay data[2]
static void SpriteCB_HikerGoingUp(struct Sprite *sprite)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
if (sprite->sTimer == 0)
2018-12-09 20:41:52 +01:00
{
2021-07-07 15:11:52 +02:00
sprite->x += 2 * sprite->centerToCornerVecX;
sprite->y += 16 + sprite->centerToCornerVecY;
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
if (++sprite->sTimer >= sprite->sDelay)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
switch (sprite->sSameDir)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
case FALSE:
2021-07-07 15:11:52 +02:00
sprite->x++;
2020-08-28 09:49:15 +02:00
if ((sprite->sTimer % 4) == 0)
2021-07-07 15:11:52 +02:00
sprite->y++;
2018-12-09 20:41:52 +01:00
break;
2020-08-28 09:49:15 +02:00
case TRUE:
// Hiker moves slower if travelling with the Cable Car
if ((sprite->sTimer % 2) != 0)
2018-12-09 20:41:52 +01:00
{
2021-07-07 15:11:52 +02:00
sprite->x++;
if ((sprite->x % 4) == 0)
sprite->y++;
2018-12-09 20:41:52 +01:00
}
break;
}
2021-07-07 15:11:52 +02:00
if (sprite->y > DISPLAY_HEIGHT)
2018-12-09 20:41:52 +01:00
DestroySprite(sprite);
}
}
2020-08-28 09:49:15 +02:00
static void SpriteCB_HikerGoingDown(struct Sprite *sprite)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
if (sprite->sTimer == 0)
2021-07-07 15:11:52 +02:00
sprite->y += 16 + sprite->centerToCornerVecY;
2018-12-09 20:41:52 +01:00
2020-08-28 09:49:15 +02:00
if (++sprite->sTimer >= sprite->sDelay)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
switch (sprite->sSameDir)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
case FALSE:
2021-07-07 15:11:52 +02:00
sprite->x--;
2020-08-28 09:49:15 +02:00
if ((sprite->sTimer % 4) == 0)
2021-07-07 15:11:52 +02:00
sprite->y--;
2018-12-09 20:41:52 +01:00
break;
2020-08-28 09:49:15 +02:00
case TRUE:
// Hiker moves slower if travelling with the Cable Car
if ((sprite->sTimer % 2) != 0)
2018-12-09 20:41:52 +01:00
{
2021-07-07 15:11:52 +02:00
sprite->x--;
if ((sprite->x % 4) == 0)
sprite->y--;
2018-12-09 20:41:52 +01:00
}
break;
}
2021-07-07 15:11:52 +02:00
if (sprite->y < 80)
2018-12-09 20:41:52 +01:00
DestroySprite(sprite);
}
}
2020-08-28 09:49:15 +02:00
#undef sTimer
static void SetBgRegs(bool8 active)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
switch (active)
2018-12-09 20:41:52 +01:00
{
case FALSE:
default:
SetGpuReg(REG_OFFSET_WININ, 0);
SetGpuReg(REG_OFFSET_WINOUT, 0);
SetGpuReg(REG_OFFSET_WIN0H, 0);
SetGpuReg(REG_OFFSET_WIN1H, 0);
SetGpuReg(REG_OFFSET_WIN0V, 0);
SetGpuReg(REG_OFFSET_WIN1V, 0);
SetGpuReg(REG_OFFSET_DISPCNT, 0);
SetGpuReg(REG_OFFSET_BG3CNT, 0);
SetGpuReg(REG_OFFSET_BG2CNT, 0);
SetGpuReg(REG_OFFSET_BG1CNT, 0);
SetGpuReg(REG_OFFSET_BG0CNT, 0);
SetGpuReg(REG_OFFSET_BG3HOFS, 0);
SetGpuReg(REG_OFFSET_BG3VOFS, 0);
SetGpuReg(REG_OFFSET_BG2HOFS, 0);
SetGpuReg(REG_OFFSET_BG2VOFS, 0);
SetGpuReg(REG_OFFSET_BG1HOFS, 0);
SetGpuReg(REG_OFFSET_BG1VOFS, 0);
SetGpuReg(REG_OFFSET_BG0HOFS, 0);
SetGpuReg(REG_OFFSET_BG0VOFS, 0);
SetGpuReg(REG_OFFSET_BLDCNT, 0);
break;
case TRUE:
SetGpuReg(REG_OFFSET_WININ, 0);
SetGpuReg(REG_OFFSET_WINOUT, 0);
SetGpuReg(REG_OFFSET_WIN0H, 0);
SetGpuReg(REG_OFFSET_WIN1H, 0);
SetGpuReg(REG_OFFSET_WIN0V, 0);
SetGpuReg(REG_OFFSET_WIN1V, 0);
2020-08-28 09:49:15 +02:00
if (!GOING_DOWN)
2018-12-09 20:41:52 +01:00
{
sCableCar->bg3HorizontalOffset = 176;
sCableCar->bg3VerticalOffset = 16;
sCableCar->bg1HorizontalOffset = 0;
sCableCar->bg1VerticalOffset = 80;
sCableCar->bg0VerticalOffset = 0;
sCableCar->bg0VerticalOffset = 0;
}
else
{
sCableCar->bg3HorizontalOffset = 96;
sCableCar->bg3VerticalOffset = 232;
sCableCar->bg1HorizontalOffset = 0;
sCableCar->bg1VerticalOffset = 4;
sCableCar->bg0VerticalOffset = 0;
sCableCar->bg0VerticalOffset = 0;
}
SetGpuReg(REG_OFFSET_BG3HOFS, sCableCar->bg3HorizontalOffset);
SetGpuReg(REG_OFFSET_BG3VOFS, sCableCar->bg3VerticalOffset);
SetGpuReg(REG_OFFSET_BG2HOFS, 0);
SetGpuReg(REG_OFFSET_BG2VOFS, 0);
SetGpuReg(REG_OFFSET_BG1HOFS, sCableCar->bg1HorizontalOffset);
SetGpuReg(REG_OFFSET_BG1VOFS, sCableCar->bg1VerticalOffset);
SetGpuReg(REG_OFFSET_BG0HOFS, sCableCar->bg0HorizontalOffset);
SetGpuReg(REG_OFFSET_BG0VOFS, sCableCar->bg0VerticalOffset);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP);
CopyBgTilemapBufferToVram(1);
CopyBgTilemapBufferToVram(2);
ShowBg(0);
ShowBg(1);
ShowBg(2);
ShowBg(3);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT2_ALL);
break;
}
}
2020-08-28 09:49:15 +02:00
static void CreateCableCarSprites(void)
2018-12-09 20:41:52 +01:00
{
u8 spriteId;
u8 i;
u8 playerGraphicsIds[2] = {
2020-08-28 09:49:15 +02:00
[MALE] = OBJ_EVENT_GFX_RIVAL_BRENDAN_NORMAL,
[FEMALE] = OBJ_EVENT_GFX_RIVAL_MAY_NORMAL
2018-12-09 20:41:52 +01:00
};
u16 rval = Random();
u8 hikerGraphicsIds[4] = {
OBJ_EVENT_GFX_HIKER,
OBJ_EVENT_GFX_CAMPER,
OBJ_EVENT_GFX_PICNICKER,
OBJ_EVENT_GFX_ZIGZAGOON_1
2018-12-09 20:41:52 +01:00
};
s16 hikerCoords[2][2] = {
2020-08-28 09:49:15 +02:00
{ 0, 80 }, // Going up
{ 240, 146 } // Going down
2018-12-09 20:41:52 +01:00
};
2020-08-28 09:49:15 +02:00
u8 hikerMovementDelayTable[4] = { 0, 60, 120, 170};
void (*hikerCallbacks[2])(struct Sprite *) = {
SpriteCB_HikerGoingUp,
SpriteCB_HikerGoingDown
2018-12-09 20:41:52 +01:00
};
2020-08-28 09:49:15 +02:00
switch (GOING_DOWN)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
case FALSE:
2018-12-09 20:41:52 +01:00
default:
2020-08-28 09:49:15 +02:00
// Create player sprite
spriteId = CreateObjectGraphicsSprite(playerGraphicsIds[gSaveBlock2Ptr->playerGender], SpriteCB_Player, 200, 73, 102);
2018-12-09 20:41:52 +01:00
if (spriteId != MAX_SPRITES)
{
gSprites[spriteId].oam.priority = 2;
2021-07-07 15:11:52 +02:00
gSprites[spriteId].x2 = 8;
gSprites[spriteId].y2 = 16;
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sXPos = 200;
gSprites[spriteId].sYPos = 73;
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
// Create car sprite
spriteId = CreateSprite(&sSpriteTemplate_CableCar[0], 176, 43, 0x67);
2021-07-07 15:11:52 +02:00
gSprites[spriteId].x2 = gSprites[spriteId].y2 = 32;
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sXPos = 176;
gSprites[spriteId].sYPos = 43;
// Create door sprite
spriteId = CreateSprite(&sSpriteTemplate_CableCar[1], 200, 99, 0x65);
2021-07-07 15:11:52 +02:00
gSprites[spriteId].x2 = 8;
gSprites[spriteId].y2 = 4;
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sXPos = 200;
gSprites[spriteId].sYPos = 99;
// Init weather
2019-12-02 01:19:47 +01:00
sCableCar->weather = WEATHER_VOLCANIC_ASH;
2020-08-28 09:49:15 +02:00
sCableCar->weatherDelay = 350;
SetCurrentAndNextWeatherNoDelay(WEATHER_SUNNY);
2018-12-09 20:41:52 +01:00
break;
2020-08-28 09:49:15 +02:00
case TRUE:
CopyToBgTilemapBufferRect_ChangePalette(0, sCableCar->groundTilemap + 0x24, 24, 26, 12, 3, 17);
// Create player sprite
spriteId = CreateObjectGraphicsSprite(playerGraphicsIds[gSaveBlock2Ptr->playerGender], SpriteCB_Player, 128, 39, 102);
2018-12-09 20:41:52 +01:00
if (spriteId != MAX_SPRITES)
{
gSprites[spriteId].oam.priority = 2;
2021-07-07 15:11:52 +02:00
gSprites[spriteId].x2 = 8;
gSprites[spriteId].y2 = 16;
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sXPos = 128;
gSprites[spriteId].sYPos = 39;
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
// Create car sprite
spriteId = CreateSprite(&sSpriteTemplate_CableCar[0], 104, 9, 0x67);
2021-07-07 15:11:52 +02:00
gSprites[spriteId].x2 = gSprites[spriteId].y2 = 32;
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sXPos = 104;
gSprites[spriteId].sYPos = 9;
// Create door sprite
spriteId = CreateSprite(&sSpriteTemplate_CableCar[1], 128, 65, 0x65);
2021-07-07 15:11:52 +02:00
gSprites[spriteId].x2 = 8;
gSprites[spriteId].y2 = 4;
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sXPos = 128;
gSprites[spriteId].sYPos = 65;
// Init weather
2018-12-09 20:41:52 +01:00
sCableCar->weather = WEATHER_SUNNY;
2020-08-28 09:49:15 +02:00
sCableCar->weatherDelay = 265;
2019-12-02 01:19:47 +01:00
SetCurrentAndNextWeatherNoDelay(WEATHER_VOLCANIC_ASH);
2018-12-09 20:41:52 +01:00
break;
}
for (i = 0; i < 9; i++)
{
2020-08-28 09:49:15 +02:00
spriteId = CreateSprite(&sSpriteTemplate_Cable, 16 * i + 96, 8 * i - 8, 0x68);
2021-07-07 15:11:52 +02:00
gSprites[spriteId].x2 = 8;
gSprites[spriteId].y2 = 8;
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
// 1/64 chance for an NPC to appear hiking on the ground below the Cable Car
2018-12-09 20:41:52 +01:00
if ((rval % 64) == 0)
{
2020-08-28 09:49:15 +02:00
// Unclear if this was intentional, but the - 1 in the below ARRAY_COUNT means the Zigzagoon is never used
spriteId = CreateObjectGraphicsSprite(hikerGraphicsIds[rval % (ARRAY_COUNT(hikerGraphicsIds) - 1)], hikerCallbacks[GOING_DOWN], hikerCoords[GOING_DOWN][0], hikerCoords[GOING_DOWN][1], 106);
2018-12-09 20:41:52 +01:00
if (spriteId != MAX_SPRITES)
{
gSprites[spriteId].oam.priority = 2;
2021-07-07 15:11:52 +02:00
gSprites[spriteId].x2 = -gSprites[spriteId].centerToCornerVecX;
gSprites[spriteId].y2 = -gSprites[spriteId].centerToCornerVecY;
2020-08-28 09:49:15 +02:00
// Randomly choose which direction the NPC is going
if (!GOING_DOWN)
2018-12-09 20:41:52 +01:00
{
if (rval % 2)
{
2021-10-29 19:37:49 +02:00
StartSpriteAnim(&gSprites[spriteId], ANIM_STD_GO_WEST);
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sSameDir = TRUE;
2021-07-07 15:11:52 +02:00
gSprites[spriteId].y += 2;
2018-12-09 20:41:52 +01:00
}
else
{
2021-10-29 19:37:49 +02:00
StartSpriteAnim(&gSprites[spriteId], ANIM_STD_GO_EAST);
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sSameDir = FALSE;
2018-12-09 20:41:52 +01:00
}
}
else
{
if (rval % 2)
{
2021-10-29 19:37:49 +02:00
StartSpriteAnim(&gSprites[spriteId], ANIM_STD_GO_EAST);
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sSameDir = TRUE;
2021-07-07 15:11:52 +02:00
gSprites[spriteId].y += 2;
2018-12-09 20:41:52 +01:00
}
else
{
2021-10-29 19:37:49 +02:00
StartSpriteAnim(&gSprites[spriteId], ANIM_STD_GO_WEST);
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sSameDir = FALSE;
2018-12-09 20:41:52 +01:00
}
}
2020-08-28 09:49:15 +02:00
gSprites[spriteId].sDelay = hikerMovementDelayTable[rval % ARRAY_COUNT(hikerMovementDelayTable)];
2018-12-09 20:41:52 +01:00
}
}
}
2020-08-28 09:49:15 +02:00
static void BufferNextGroundSegment(void)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
u8 i, j, k;
2018-12-09 20:41:52 +01:00
u8 offset;
2020-08-28 09:49:15 +02:00
for (i = 0, k = 0, offset = 0x24 * (sCableCar->groundTilemapOffset + 2); i < 3; i++)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
for (j = 0; j < ARRAY_COUNT(sCableCar->groundTileBuffer[0]); j++)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
sCableCar->groundTileBuffer[i][j] = sCableCar->groundTilemap[offset++];
sCableCar->groundTileBuffer[i + 3][j] = sCableCar->groundTilemap[k];
sCableCar->groundTileBuffer[i + 6][j] = (sCableCar->groundTilemap + 0x24)[k];
2018-12-09 20:41:52 +01:00
k++;
}
}
2020-08-28 09:49:15 +02:00
sCableCar->groundTilemapOffset = (sCableCar->groundTilemapOffset + 1) % 3;
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
static void AnimateGroundGoingUp(void)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
sCableCar->groundTimer = (sCableCar->groundTimer + 1) % 96;
sCableCar->bg0HorizontalOffset = sCableCar->groundXBase - sCableCar->groundXOffset;
sCableCar->bg0VerticalOffset = sCableCar->groundYBase - sCableCar->groundYOffset;
sCableCar->groundXOffset++;
if ((sCableCar->groundXOffset % 4) == 0)
sCableCar->groundYOffset++;
if (sCableCar->groundXOffset > 16)
DrawNextGroundSegmentGoingUp();
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
static void AnimateGroundGoingDown(void)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
sCableCar->groundTimer = (sCableCar->groundTimer + 1) % 96;
sCableCar->bg0HorizontalOffset = sCableCar->groundXBase + sCableCar->groundXOffset;
sCableCar->bg0VerticalOffset = sCableCar->groundYBase + sCableCar->groundYOffset;
sCableCar->groundXOffset++;
if ((sCableCar->groundXOffset % 4) == 0)
sCableCar->groundYOffset++;
if (sCableCar->groundXOffset > 16)
DrawNextGroundSegmentGoingDown();
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
static void DrawNextGroundSegmentGoingUp(void)
2018-12-09 20:41:52 +01:00
{
u8 i = 0;
2020-08-28 09:49:15 +02:00
sCableCar->groundXOffset = sCableCar->groundYOffset = 0;
sCableCar->groundXBase = sCableCar->bg0HorizontalOffset;
sCableCar->groundYBase = sCableCar->bg0VerticalOffset;
sCableCar->groundSegmentXStart = (sCableCar->groundSegmentXStart + 30) % 32;
sCableCar->groundTileIdx -= 2;
2020-09-03 22:17:29 +02:00
sGroundSegmentY_Up = (sCableCar->groundSegmentYStart + 23) % 32;
2020-08-28 09:49:15 +02:00
// Draw next segment
for (i = 0; i < ARRAY_COUNT(sCableCar->groundTileBuffer); i++)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
sGroundX_Up = sCableCar->groundSegmentXStart;
2020-09-03 22:17:29 +02:00
sGroundY_Up = (sGroundSegmentY_Up + i) % 32;
2020-08-28 09:49:15 +02:00
FillBgTilemapBufferRect(0, sCableCar->groundTileBuffer[i][sCableCar->groundTileIdx], sGroundX_Up, sGroundY_Up, 1, 1, 17);
sGroundX_Up = (sGroundX_Up + 1) % 32;
FillBgTilemapBufferRect(0, sCableCar->groundTileBuffer[i][sCableCar->groundTileIdx + 1], sGroundX_Up, sGroundY_Up, 1, 1, 17);
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
// Erase old segment
sGroundX_Up = (sCableCar->groundSegmentXStart + 30) % 32;
FillBgTilemapBufferRect(0, 0, sGroundX_Up, 0, 2, 32, 17);
if (sCableCar->groundTileIdx == 0)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
sCableCar->groundSegmentYStart = (sCableCar->groundSegmentYStart + 29) % 32;
sCableCar->groundTileIdx = 12;
BufferNextGroundSegment();
sGroundX_Up = (sCableCar->groundSegmentYStart + 1) % 32;
FillBgTilemapBufferRect(0, 0, 0, sGroundX_Up, 32, 9, 17);
2018-12-09 20:41:52 +01:00
}
}
2020-08-28 09:49:15 +02:00
static void DrawNextGroundSegmentGoingDown(void)
2018-12-09 20:41:52 +01:00
{
u8 i = 0;
2020-08-28 09:49:15 +02:00
sCableCar->groundXOffset = sCableCar->groundYOffset = 0;
sCableCar->groundXBase = sCableCar->bg0HorizontalOffset;
sCableCar->groundYBase = sCableCar->bg0VerticalOffset;
sCableCar->groundSegmentXStart = (sCableCar->groundSegmentXStart + 2) % 32;
sCableCar->groundTileIdx += 2;
sGroundSegmentY_Down = sCableCar->groundSegmentYStart;
2020-08-28 09:49:15 +02:00
// Draw next segment
for (i = 0; i < ARRAY_COUNT(sCableCar->groundTileBuffer); i++)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
sGroundX_Down = sCableCar->groundSegmentXStart;
sGroundY_Down = (sGroundSegmentY_Down + i) % 32;
FillBgTilemapBufferRect(0, sCableCar->groundTileBuffer[i][sCableCar->groundTileIdx], sGroundX_Down, sGroundY_Down, 1, 1, 17);
sGroundX_Down = (sGroundX_Down + 1) % 32;
FillBgTilemapBufferRect(0, sCableCar->groundTileBuffer[i][sCableCar->groundTileIdx + 1], sGroundX_Down, sGroundY_Down, 1, 1, 17);
2018-12-09 20:41:52 +01:00
}
2020-08-28 09:49:15 +02:00
// Erase old segment
sGroundY_Down = (sCableCar->groundSegmentYStart + 23) % 32;
FillBgTilemapBufferRect(0, 0, sCableCar->groundSegmentXStart, sGroundY_Down, 2, 9, 17);
if (sCableCar->groundTileIdx == 10)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
sCableCar->groundSegmentYStart = (sCableCar->groundSegmentYStart + 3) % 32;
sCableCar->groundTileIdx = -2;
BufferNextGroundSegment();
2018-12-09 20:41:52 +01:00
}
}
2020-08-28 09:49:15 +02:00
static void InitGroundTilemapData(bool8 goingDown)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
switch (goingDown)
2018-12-09 20:41:52 +01:00
{
2020-08-28 09:49:15 +02:00
case FALSE:
2018-12-09 20:41:52 +01:00
default:
2020-08-28 09:49:15 +02:00
sCableCar->groundTilemapOffset = 2;
sCableCar->groundSegmentXStart = 0;
sCableCar->groundSegmentYStart = 20;
sCableCar->groundTileIdx = 12;
BufferNextGroundSegment();
DrawNextGroundSegmentGoingUp();
2018-12-09 20:41:52 +01:00
break;
2020-08-28 09:49:15 +02:00
case TRUE:
sCableCar->groundTilemapOffset = 2;
sCableCar->groundSegmentXStart = 28;
sCableCar->groundSegmentYStart = 20;
sCableCar->groundTileIdx = 4;
BufferNextGroundSegment();
DrawNextGroundSegmentGoingDown();
2018-12-09 20:41:52 +01:00
break;
}
2020-08-28 09:49:15 +02:00
sCableCar->groundTimer = 0;
2018-12-09 20:41:52 +01:00
}
2019-04-02 00:31:10 +02:00