summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDiegoisawesome <Diegoisawesome@users.noreply.github.com>2018-04-18 14:12:51 -0500
committerGitHub <noreply@github.com>2018-04-18 14:12:51 -0500
commitd10844f1feaf1e9add59685e037fab7ad0027dce (patch)
tree932a43254cff7cd4b3d480ab1a2c25cf9efa0b95 /src
parent4e63a52832f4a443e24df4f38503e3b449b54e45 (diff)
parentdc759a501b7dfa183b64ea68fbd9437f04e39e74 (diff)
Merge pull request #237 from KDSKardabox/master
Decompile mon markings, rotating_gate & field_camera
Diffstat (limited to 'src')
-rw-r--r--src/bike.c3
-rw-r--r--src/decoration.c20
-rw-r--r--src/field_camera.c491
-rw-r--r--src/mon_markings.c611
-rw-r--r--src/overworld.c27
-rw-r--r--src/rotating_gate.c1188
-rw-r--r--src/text_window.c40
7 files changed, 2321 insertions, 59 deletions
diff --git a/src/bike.c b/src/bike.c
index 64af7c711..782eceb8e 100644
--- a/src/bike.c
+++ b/src/bike.c
@@ -12,7 +12,6 @@
extern bool8 gBikeCyclingChallenge;
extern u8 gBikeCollisions;
-extern bool8 gUnknown_02037348;
extern u8 sub_8093514(u8 direction);
extern u8 sub_808B980(u8 direction);
@@ -989,7 +988,7 @@ bool8 player_should_look_direction_be_enforced_upon_movement(void)
void GetOnOffBike(u8 transitionFlags)
{
- gUnknown_02037348 = FALSE;
+ gUnusedBikeCameraAheadPanback = FALSE;
if (gPlayerAvatar.flags & (PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE))
{
diff --git a/src/decoration.c b/src/decoration.c
index a0855db69..f376c2115 100644
--- a/src/decoration.c
+++ b/src/decoration.c
@@ -1305,12 +1305,12 @@ void sub_8128060(u8 taskId)
void ConfigureCameraObjectForPlacingDecoration(struct PlaceDecorationGraphicsDataBuffer *data, u8 decor)
{
- sDecor_CameraSpriteObjectIdx1 = gSprites[gUnknown_03005DD0.unk4].data[0];
- gUnknown_03005DD0.unk4 = gpu_pal_decompress_alloc_tag_and_upload(data, decor);
- gSprites[gUnknown_03005DD0.unk4].oam.priority = 1;
- gSprites[gUnknown_03005DD0.unk4].callback = sub_81292D0;
- gSprites[gUnknown_03005DD0.unk4].pos1.x = gUnknown_085A7250[data->decoration->shape].x;
- gSprites[gUnknown_03005DD0.unk4].pos1.y = gUnknown_085A7250[data->decoration->shape].y;
+ sDecor_CameraSpriteObjectIdx1 = gSprites[gUnknown_03005DD0.spriteId].data[0];
+ gUnknown_03005DD0.spriteId = gpu_pal_decompress_alloc_tag_and_upload(data, decor);
+ gSprites[gUnknown_03005DD0.spriteId].oam.priority = 1;
+ gSprites[gUnknown_03005DD0.spriteId].callback = sub_81292D0;
+ gSprites[gUnknown_03005DD0.spriteId].pos1.x = gUnknown_085A7250[data->decoration->shape].x;
+ gSprites[gUnknown_03005DD0.spriteId].pos1.y = gUnknown_085A7250[data->decoration->shape].y;
}
void SetUpPlacingDecorationPlayerAvatar(u8 taskId, struct PlaceDecorationGraphicsDataBuffer *data)
@@ -1332,7 +1332,7 @@ void SetUpPlacingDecorationPlayerAvatar(u8 taskId, struct PlaceDecorationGraphic
}
gSprites[sDecor_CameraSpriteObjectIdx2].oam.priority = 1;
DestroySprite(&gSprites[sDecor_CameraSpriteObjectIdx1]);
- sDecor_CameraSpriteObjectIdx1 = gUnknown_03005DD0.unk4;
+ sDecor_CameraSpriteObjectIdx1 = gUnknown_03005DD0.spriteId;
}
void sub_812826C(u8 taskId)
@@ -2251,9 +2251,9 @@ bool8 sub_81299AC(u8 taskId)
void SetUpPuttingAwayDecorationPlayerAvatar(void)
{
player_get_direction_lower_nybble();
- sDecor_CameraSpriteObjectIdx1 = gSprites[gUnknown_03005DD0.unk4].data[0];
+ sDecor_CameraSpriteObjectIdx1 = gSprites[gUnknown_03005DD0.spriteId].data[0];
sub_812A39C();
- gUnknown_03005DD0.unk4 = CreateSprite(&gUnknown_085A7404, 0x78, 0x50, 0);
+ gUnknown_03005DD0.spriteId = CreateSprite(&gUnknown_085A7404, 0x78, 0x50, 0);
if (gSaveBlock2Ptr->playerGender == MALE)
{
sDecor_CameraSpriteObjectIdx2 = AddPseudoFieldObject(0xC1, SpriteCallbackDummy, 0x88, 0x48, 0);
@@ -2264,7 +2264,7 @@ void SetUpPuttingAwayDecorationPlayerAvatar(void)
}
gSprites[sDecor_CameraSpriteObjectIdx2].oam.priority = 1;
DestroySprite(&gSprites[sDecor_CameraSpriteObjectIdx1]);
- sDecor_CameraSpriteObjectIdx1 = gUnknown_03005DD0.unk4;
+ sDecor_CameraSpriteObjectIdx1 = gUnknown_03005DD0.spriteId;
gSprites[sDecor_CameraSpriteObjectIdx1].oam.priority = 1;
}
diff --git a/src/field_camera.c b/src/field_camera.c
index 17ced6aa5..f653e0bf1 100644
--- a/src/field_camera.c
+++ b/src/field_camera.c
@@ -1,9 +1,18 @@
-
-// Includes
#include "global.h"
+#include "berry.h"
+#include "bike.h"
+#include "field_camera.h"
+#include "field_player_avatar.h"
+#include "fieldmap.h"
+#include "field_map_obj.h"
+#include "gpu_regs.h"
+#include "menu.h"
+#include "overworld.h"
+#include "rotating_gate.h"
+#include "sprite.h"
+#include "text.h"
// Static type declarations
-
struct FieldCameraUnknownStruct
{
u8 unk0;
@@ -13,16 +22,474 @@ struct FieldCameraUnknownStruct
bool8 unk4;
};
-// Static RAM declarations
+// static functions
+static void RedrawMapSliceNorth(struct FieldCameraUnknownStruct *a, const struct MapData *mapData);
+static void RedrawMapSliceSouth(struct FieldCameraUnknownStruct *a, const struct MapData *mapData);
+static void RedrawMapSliceEast(struct FieldCameraUnknownStruct *a, const struct MapData *mapData);
+static void RedrawMapSliceWest(struct FieldCameraUnknownStruct *a, const struct MapData *mapData);
+static s32 MapPosToBgTilemapOffset(struct FieldCameraUnknownStruct *a, s32 x, s32 y);
+static void DrawWholeMapViewInternal(int x, int y, const struct MapData *mapData);
+static void DrawMetatileAt(const struct MapData *mapData, u16, int, int);
+static void DrawMetatile(s32 a, u16 *b, u16 c);
+static void CameraPanningCB_PanAhead(void);
+
+// IWRAM bss vars
+static IWRAM_DATA struct FieldCameraUnknownStruct gUnknown_03000E20;
+static IWRAM_DATA s16 gUnknown_03000E28;
+static IWRAM_DATA s16 gUnknown_03000E2A;
+static IWRAM_DATA u8 gUnknown_03000E2C;
+static IWRAM_DATA void (*gUnknown_03000E30)(void);
+
+// text
+static void move_tilemap_camera_to_upper_left_corner_(struct FieldCameraUnknownStruct *a)
+{
+ a->unk2 = 0;
+ a->unk3 = 0;
+ a->unk0 = 0;
+ a->unk1 = 0;
+ a->unk4 = TRUE;
+}
+
+static void tilemap_move_something(struct FieldCameraUnknownStruct *a, u32 b, u32 c)
+{
+ a->unk2 += b;
+ a->unk2 %= 32;
+ a->unk3 += c;
+ a->unk3 %= 32;
+}
+
+static void coords8_add(struct FieldCameraUnknownStruct *a, u32 b, u32 c)
+{
+ a->unk0 += b;
+ a->unk1 += c;
+}
+
+void move_tilemap_camera_to_upper_left_corner(void)
+{
+ move_tilemap_camera_to_upper_left_corner_(&gUnknown_03000E20);
+}
+
+void FieldUpdateBgTilemapScroll(void)
+{
+ u32 r4, r5;
+ r5 = gUnknown_03000E20.unk0 + gUnknown_03000E28;
+ r4 = gUnknown_03000E2A + gUnknown_03000E20.unk1 + 8;
+
+ SetGpuReg(REG_OFFSET_BG1HOFS, r5);
+ SetGpuReg(REG_OFFSET_BG1VOFS, r4);
+ SetGpuReg(REG_OFFSET_BG2HOFS, r5);
+ SetGpuReg(REG_OFFSET_BG2VOFS, r4);
+ SetGpuReg(REG_OFFSET_BG3HOFS, r5);
+ SetGpuReg(REG_OFFSET_BG3VOFS, r4);
+}
+
+void sub_8089C08(s16 *a, s16 *b)
+{
+ *a = gUnknown_03000E20.unk0 + gUnknown_03000E28;
+ *b = gUnknown_03000E20.unk1 + gUnknown_03000E2A + 8;
+}
+
+void DrawWholeMapView(void)
+{
+ DrawWholeMapViewInternal(gSaveBlock1Ptr->pos.x, gSaveBlock1Ptr->pos.y, gMapHeader.mapData);
+ gUnknown_03000E20.unk4 = TRUE;
+}
+
+static void DrawWholeMapViewInternal(int x, int y, const struct MapData *mapData)
+{
+ u8 i;
+ u8 j;
+ u32 r6;
+ u8 temp;
+
+ for (i = 0; i < 32; i += 2)
+ {
+ temp = gUnknown_03000E20.unk3 + i;
+ if (temp >= 32)
+ temp -= 32;
+ r6 = temp * 32;
+ for (j = 0; j < 32; j += 2)
+ {
+ temp = gUnknown_03000E20.unk2 + j;
+ if (temp >= 32)
+ temp -= 32;
+ DrawMetatileAt(mapData, r6 + temp, x + j / 2, y + i / 2);
+ }
+ }
+}
+
+static void RedrawMapSlicesForCameraUpdate(struct FieldCameraUnknownStruct *a, int x, int y)
+{
+ const struct MapData *mapData = gMapHeader.mapData;
+
+ if (x > 0)
+ RedrawMapSliceWest(a, mapData);
+ if (x < 0)
+ RedrawMapSliceEast(a, mapData);
+ if (y > 0)
+ RedrawMapSliceNorth(a, mapData);
+ if (y < 0)
+ RedrawMapSliceSouth(a, mapData);
+ a->unk4 = TRUE;
+}
+
+static void RedrawMapSliceNorth(struct FieldCameraUnknownStruct *a, const struct MapData *mapData)
+{
+ u8 i;
+ u8 temp;
+ u32 r7;
+
+ temp = a->unk3 + 28;
+ if (temp >= 32)
+ temp -= 32;
+ r7 = temp * 32;
+ for (i = 0; i < 32; i += 2)
+ {
+ temp = a->unk2 + i;
+ if (temp >= 32)
+ temp -= 32;
+ DrawMetatileAt(mapData, r7 + temp, gSaveBlock1Ptr->pos.x + i / 2, gSaveBlock1Ptr->pos.y + 14);
+ }
+}
+
+static void RedrawMapSliceSouth(struct FieldCameraUnknownStruct *a, const struct MapData *mapData)
+{
+ u8 i;
+ u8 temp;
+ u32 r7 = a->unk3 * 32;
+
+ for (i = 0; i < 32; i += 2)
+ {
+ temp = a->unk2 + i;
+ if (temp >= 32)
+ temp -= 32;
+ DrawMetatileAt(mapData, r7 + temp, gSaveBlock1Ptr->pos.x + i / 2, gSaveBlock1Ptr->pos.y);
+ }
+}
+
+static void RedrawMapSliceEast(struct FieldCameraUnknownStruct *a, const struct MapData *mapData)
+{
+ u8 i;
+ u8 temp;
+ u32 r6 = a->unk2;
+
+ for (i = 0; i < 32; i += 2)
+ {
+ temp = a->unk3 + i;
+ if (temp >= 32)
+ temp -= 32;
+ DrawMetatileAt(mapData, temp * 32 + r6, gSaveBlock1Ptr->pos.x, gSaveBlock1Ptr->pos.y + i / 2);
+ }
+}
+
+static void RedrawMapSliceWest(struct FieldCameraUnknownStruct *a, const struct MapData *mapData)
+{
+ u8 i;
+ u8 temp;
+ u8 r5 = a->unk2 + 28;
+
+ if (r5 >= 32)
+ r5 -= 32;
+ for (i = 0; i < 32; i += 2)
+ {
+ temp = a->unk3 + i;
+ if (temp >= 32)
+ temp -= 32;
+ DrawMetatileAt(mapData, temp * 32 + r5, gSaveBlock1Ptr->pos.x + 14, gSaveBlock1Ptr->pos.y + i / 2);
+ }
+}
+
+void CurrentMapDrawMetatileAt(int a, int b)
+{
+ int offset = MapPosToBgTilemapOffset(&gUnknown_03000E20, a, b);
+
+ if (offset >= 0)
+ {
+ DrawMetatileAt(gMapHeader.mapData, offset, a, b);
+ gUnknown_03000E20.unk4 = TRUE;
+ }
+}
+
+void DrawDoorMetatileAt(int x, int y, u16 *arr)
+{
+ int offset = MapPosToBgTilemapOffset(&gUnknown_03000E20, x, y);
+
+ if (offset >= 0)
+ {
+ DrawMetatile(1, arr, offset);
+ gUnknown_03000E20.unk4 = TRUE;
+ }
+}
+
+static void DrawMetatileAt(const struct MapData *mapData, u16 b, int c, int d)
+{
+ u16 metatileId = MapGridGetMetatileIdAt(c, d);
+ u16 *metatiles;
+
+ if (metatileId > 1024)
+ metatileId = 0;
+ if (metatileId < 512)
+ metatiles = mapData->primaryTileset->metatiles;
+ else
+ {
+ metatiles = mapData->secondaryTileset->metatiles;
+ metatileId -= 512;
+ }
+ DrawMetatile(MapGridGetMetatileLayerTypeAt(c, d), metatiles + metatileId * 8, b);
+}
+
+static void DrawMetatile(s32 a, u16 *b, u16 c)
+{
+ switch (a)
+ {
+ case 2:
+ gBGTilemapBuffers3[c] = b[0];
+ gBGTilemapBuffers3[c + 1] = b[1];
+ gBGTilemapBuffers3[c + 0x20] = b[2];
+ gBGTilemapBuffers3[c + 0x21] = b[3];
+
+ gBGTilemapBuffers1[c] = 0;
+ gBGTilemapBuffers1[c + 1] = 0;
+ gBGTilemapBuffers1[c + 0x20] = 0;
+ gBGTilemapBuffers1[c + 0x21] = 0;
+
+ gBGTilemapBuffers2[c] = b[4];
+ gBGTilemapBuffers2[c + 1] = b[5];
+ gBGTilemapBuffers2[c + 0x20] = b[6];
+ gBGTilemapBuffers2[c + 0x21] = b[7];
+ break;
+ case 1:
+ gBGTilemapBuffers3[c] = b[0];
+ gBGTilemapBuffers3[c + 1] = b[1];
+ gBGTilemapBuffers3[c + 0x20] = b[2];
+ gBGTilemapBuffers3[c + 0x21] = b[3];
+
+ gBGTilemapBuffers1[c] = b[4];
+ gBGTilemapBuffers1[c + 1] = b[5];
+ gBGTilemapBuffers1[c + 0x20] = b[6];
+ gBGTilemapBuffers1[c + 0x21] = b[7];
+
+ gBGTilemapBuffers2[c] = 0;
+ gBGTilemapBuffers2[c + 1] = 0;
+ gBGTilemapBuffers2[c + 0x20] = 0;
+ gBGTilemapBuffers2[c + 0x21] = 0;
+ break;
+ case 0:
+ gBGTilemapBuffers3[c] = 0x3014;
+ gBGTilemapBuffers3[c + 1] = 0x3014;
+ gBGTilemapBuffers3[c + 0x20] = 0x3014;
+ gBGTilemapBuffers3[c + 0x21] = 0x3014;
+
+ gBGTilemapBuffers1[c] = b[0];
+ gBGTilemapBuffers1[c + 1] = b[1];
+ gBGTilemapBuffers1[c + 0x20] = b[2];
+ gBGTilemapBuffers1[c + 0x21] = b[3];
-IWRAM_DATA struct FieldCameraUnknownStruct gUnknown_03000E20;
-IWRAM_DATA s16 gUnknown_03000E28;
-IWRAM_DATA s16 gUnknown_03000E2A;
-IWRAM_DATA u8 gUnknown_03000E2C;
-IWRAM_DATA void (*gUnknown_03000E30)(void);
+ gBGTilemapBuffers2[c] = b[4];
+ gBGTilemapBuffers2[c + 1] = b[5];
+ gBGTilemapBuffers2[c + 0x20] = b[6];
+ gBGTilemapBuffers2[c + 0x21] = b[7];
+ break;
+ }
+ schedule_bg_copy_tilemap_to_vram(1);
+ schedule_bg_copy_tilemap_to_vram(2);
+ schedule_bg_copy_tilemap_to_vram(3);
+}
+
+static s32 MapPosToBgTilemapOffset(struct FieldCameraUnknownStruct *a, s32 x, s32 y)
+{
+ x -= gSaveBlock1Ptr->pos.x;
+ x *= 2;
+ if (x >= 32 || x < 0)
+ return -1;
+ x = x + a->unk2;
+ if (x >= 32)
+ x -= 32;
+
+ y = (y - gSaveBlock1Ptr->pos.y) * 2;
+ if (y >= 32 || y < 0)
+ return -1;
+ y = y + a->unk3;
+ if (y >= 32)
+ y -= 32;
+
+ return y * 32 + x;
+}
+
+static void CameraUpdateCallback(struct CameraObject *a)
+{
+ if (a->spriteId != 0)
+ {
+ a->unk8 = gSprites[a->spriteId].data[2];
+ a->unkC = gSprites[a->spriteId].data[3];
+ }
+}
+
+void ResetCameraUpdateInfo(void)
+{
+ gUnknown_03005DD0.unk8 = 0;
+ gUnknown_03005DD0.unkC = 0;
+ gUnknown_03005DD0.x = 0;
+ gUnknown_03005DD0.y = 0;
+ gUnknown_03005DD0.spriteId = 0;
+ gUnknown_03005DD0.callback = NULL;
+}
+
+u32 InitCameraUpdateCallback(u8 a)
+{
+ if (gUnknown_03005DD0.spriteId != 0)
+ DestroySprite(&gSprites[gUnknown_03005DD0.spriteId]);
+ gUnknown_03005DD0.spriteId = AddCameraObject(a);
+ gUnknown_03005DD0.callback = CameraUpdateCallback;
+ return 0;
+}
+
+void CameraUpdate(void)
+{
+ int deltaX;
+ int deltaY;
+ int r0;
+ int r1;
+ int r7;
+ int r8;
+
+ if (gUnknown_03005DD0.callback != NULL)
+ gUnknown_03005DD0.callback(&gUnknown_03005DD0);
+ r7 = gUnknown_03005DD0.unk8;
+ r8 = gUnknown_03005DD0.unkC;
+ deltaX = 0;
+ deltaY = 0;
+ r1 = gUnknown_03005DD0.x;
+ r0 = gUnknown_03005DD0.y;
+
+
+ if (r1 == 0 && r7 != 0)
+ {
+ if (r7 > 0)
+ deltaX = 1;
+ else
+ deltaX = -1;
+ }
+ if (r0 == 0 && r8 != 0)
+ {
+ if (r8 > 0)
+ deltaY = 1;
+ else
+ deltaY = -1;
+ }
+ if (r1 != 0 && r1 == -r7)
+ {
+ if (r7 > 0)
+ deltaX = 1;
+ else
+ deltaX = -1;
+ }
+ if (r0 != 0 && r0 == -r8)
+ {
+ if (r8 > 0)
+ deltaX = 1;
+ else
+ deltaX = -1;
+ }
+
+ gUnknown_03005DD0.x += r7;
+ gUnknown_03005DD0.x = gUnknown_03005DD0.x - 16 * (gUnknown_03005DD0.x / 16);
+ gUnknown_03005DD0.y += r8;
+ gUnknown_03005DD0.y = gUnknown_03005DD0.y - 16 * (gUnknown_03005DD0.y / 16);
+
+ if (deltaX != 0 || deltaY != 0)
+ {
+ CameraMove(deltaX, deltaY);
+ UpdateFieldObjectsForCameraUpdate(deltaX, deltaY);
+ RotatingGatePuzzleCameraUpdate(deltaX, deltaY);
+ ResetBerryTreeSparkleFlags();
+ tilemap_move_something(&gUnknown_03000E20, deltaX * 2, deltaY * 2);
+ RedrawMapSlicesForCameraUpdate(&gUnknown_03000E20, deltaX * 2, deltaY * 2);
+ }
+
+ coords8_add(&gUnknown_03000E20, r7, r8);
+ gUnknown_03005DEC -= r7;
+ gUnknown_03005DE8 -= r8;
+}
+
+void camera_move_and_redraw(int a, int b) //unused
+{
+ CameraMove(a, b);
+ UpdateFieldObjectsForCameraUpdate(a, b);
+ DrawWholeMapView();
+ gUnknown_03005DEC -= a * 16;
+ gUnknown_03005DE8 -= b * 16;
+}
+
+void SetCameraPanningCallback(void (*a)(void))
+{
+ gUnknown_03000E30 = a;
+}
+
+void SetCameraPanning(s16 a, s16 b)
+{
+ gUnknown_03000E28 = a;
+ gUnknown_03000E2A = b + 32;
+}
+
+void InstallCameraPanAheadCallback(void)
+{
+ gUnknown_03000E30 = CameraPanningCB_PanAhead;
+ gUnknown_03000E2C = 0;
+ gUnknown_03000E28 = 0;
+ gUnknown_03000E2A = 32;
+}
+
+void UpdateCameraPanning(void)
+{
+ if (gUnknown_03000E30 != NULL)
+ gUnknown_03000E30();
+ //Update sprite offset of overworld objects
+ gSpriteCoordOffsetX = gUnknown_03005DEC - gUnknown_03000E28;
+ gSpriteCoordOffsetY = gUnknown_03005DE8 - gUnknown_03000E2A - 8;
+}
+
+static void CameraPanningCB_PanAhead(void)
+{
+ u8 var;
-// Static ROM declarations
+ if (gUnusedBikeCameraAheadPanback == FALSE)
+ {
+ InstallCameraPanAheadCallback();
+ }
+ else
+ {
+ // this code is never reached.
+ if (gPlayerAvatar.tileTransitionState == T_TILE_TRANSITION)
+ {
+ gUnknown_03000E2C ^= 1;
+ if (gUnknown_03000E2C == 0)
+ return;
+ }
+ else
+ {
+ gUnknown_03000E2C = 0;
+ }
-// .rodata
+ var = player_get_direction_upper_nybble();
+ if (var == 2)
+ {
+ if (gUnknown_03000E2A > -8)
+ gUnknown_03000E2A -= 2;
+ }
+ else if (var == 1)
+ {
+ if (gUnknown_03000E2A < 72)
+ gUnknown_03000E2A += 2;
+ }
+ else if (gUnknown_03000E2A < 32)
+ {
+ gUnknown_03000E2A += 2;
+ }
+ else if (gUnknown_03000E2A > 32)
+ {
+ gUnknown_03000E2A -= 2;
+ }
+ }
+}
-// .text
diff --git a/src/mon_markings.c b/src/mon_markings.c
new file mode 100644
index 000000000..147872ab6
--- /dev/null
+++ b/src/mon_markings.c
@@ -0,0 +1,611 @@
+#include "global.h"
+#include "dma3.h"
+#include "graphics.h"
+#include "main.h"
+#include "menu_indicators.h"
+#include "mon_markings.h"
+#include "constants/songs.h"
+#include "sound.h"
+#include "sprite.h"
+#include "text_window.h"
+
+#define MENU_TEXT_SPRITE_X_OFFSET 32
+
+// static functions
+static void sub_811FC80(s16, s16, u16, u16);
+static void TaskDummy7(struct Sprite *);
+static void sub_811FF40(struct Sprite *);
+static void sub_811FF7C(struct Sprite *);
+static struct Sprite *sub_811FFD4(u16, u16, const u16 *, u16);
+
+// .rodata
+static const u16 gUnknown_0859E65C[] = INCBIN_U16("graphics/misc/mon_markings.gbapal");
+static const u8 gUnknown_0859E67C[] = INCBIN_U8("graphics/misc/mon_markings.4bpp");
+
+static const struct OamData gUnknown_0859EE7C =
+{
+ .y = 0,
+ .affineMode = 0,
+ .objMode = 0,
+ .mosaic = 0,
+ .bpp = 0,
+ .shape = 0,
+ .x = 0,
+ .matrixNum = 0,
+ .size = 3,
+ .tileNum = 0,
+ .priority = 0,
+ .paletteNum = 0,
+ .affineParam = 0,
+};
+
+static const struct OamData gUnknown_0859EE84 =
+{
+ .y = 0,
+ .affineMode = 0,
+ .objMode = 0,
+ .mosaic = 0,
+ .bpp = 0,
+ .shape = 0,
+ .x = 0,
+ .matrixNum = 0,
+ .size = 0,
+ .tileNum = 0,
+ .priority = 0,
+ .paletteNum = 0,
+ .affineParam = 0,
+};
+
+static const union AnimCmd gUnknown_0859EE8C[] =
+{
+ ANIMCMD_FRAME(0, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EE94[] =
+{
+ ANIMCMD_FRAME(1, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EE9C[] =
+{
+ ANIMCMD_FRAME(2, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EEA4[] =
+{
+ ANIMCMD_FRAME(3, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EEAC[] =
+{
+ ANIMCMD_FRAME(4, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EEB4[] =
+{
+ ANIMCMD_FRAME(5, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EEBC[] =
+{
+ ANIMCMD_FRAME(6, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EEC4[] =
+{
+ ANIMCMD_FRAME(7, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EECC[] =
+{
+ ANIMCMD_FRAME(8, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EED4[] =
+{
+ ANIMCMD_FRAME(9, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const gUnknown_0859EEDC[] =
+{
+ gUnknown_0859EE8C,
+ gUnknown_0859EE94,
+ gUnknown_0859EE9C,
+ gUnknown_0859EEA4,
+ gUnknown_0859EEAC,
+ gUnknown_0859EEB4,
+ gUnknown_0859EEBC,
+ gUnknown_0859EEC4,
+ gUnknown_0859EECC,
+ gUnknown_0859EED4,
+};
+
+static const union AnimCmd gUnknown_0859EF04[] =
+{
+ ANIMCMD_FRAME(0, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF0C[] =
+{
+ ANIMCMD_FRAME(64, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const gUnknown_0859EF14[] =
+{
+ gUnknown_0859EF04,
+ gUnknown_0859EF0C,
+};
+
+static const struct OamData gUnknown_0859EF1C =
+{
+ .y = 0,
+ .affineMode = 0,
+ .objMode = 0,
+ .mosaic = 0,
+ .bpp = 0,
+ .shape = 1,
+ .x = 0,
+ .matrixNum = 0,
+ .size = 1,
+ .tileNum = 0,
+ .priority = 0,
+ .paletteNum = 0,
+ .affineParam = 0,
+};
+
+static const union AnimCmd gUnknown_0859EF24[] =
+{
+ ANIMCMD_FRAME(0, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF2C[] =
+{
+ ANIMCMD_FRAME(4, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF34[] =
+{
+ ANIMCMD_FRAME(8, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF3C[] =
+{
+ ANIMCMD_FRAME(12, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF44[] =
+{
+ ANIMCMD_FRAME(16, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF4C[] =
+{
+ ANIMCMD_FRAME(20, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF54[] =
+{
+ ANIMCMD_FRAME(24, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF5C[] =
+{
+ ANIMCMD_FRAME(28, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF64[] =
+{
+ ANIMCMD_FRAME(32, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF6C[] =
+{
+ ANIMCMD_FRAME(36, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF74[] =
+{
+ ANIMCMD_FRAME(40, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF7C[] =
+{
+ ANIMCMD_FRAME(44, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF84[] =
+{
+ ANIMCMD_FRAME(48, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF8C[] =
+{
+ ANIMCMD_FRAME(52, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF94[] =
+{
+ ANIMCMD_FRAME(56, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd gUnknown_0859EF9C[] =
+{
+ ANIMCMD_FRAME(60, 5),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd *const gUnknown_0859EFA4[] =
+{
+ gUnknown_0859EF24,
+ gUnknown_0859EF2C,
+ gUnknown_0859EF34,
+ gUnknown_0859EF3C,
+ gUnknown_0859EF44,
+ gUnknown_0859EF4C,
+ gUnknown_0859EF54,
+ gUnknown_0859EF5C,
+ gUnknown_0859EF64,
+ gUnknown_0859EF6C,
+ gUnknown_0859EF74,
+ gUnknown_0859EF7C,
+ gUnknown_0859EF84,
+ gUnknown_0859EF8C,
+ gUnknown_0859EF94,
+ gUnknown_0859EF9C,
+};
+
+static EWRAM_DATA struct PokemonMarkMenu *sMenu = NULL;
+
+void sub_811F90C(struct PokemonMarkMenu *ptr)
+{
+ sMenu = ptr;
+}
+
+void sub_811F918(void)
+{
+ const struct TilesPal *frame = GetWindowFrameTilesPal(gSaveBlock2Ptr->optionsWindowFrameType);
+ sMenu->frameTiles = frame->tiles;
+ sMenu->framePalette = frame->pal;
+ sMenu->tileLoadState = 0;
+ CpuFill16(0, sMenu->menuWindowSpriteTiles, sizeof(sMenu->menuWindowSpriteTiles));
+}
+
+bool8 sub_811F960(void)
+{
+ u16 i;
+ u8 *dest = sMenu->menuWindowSpriteTiles + sMenu->tileLoadState * 0x100;
+
+ switch (sMenu->tileLoadState)
+ {
+ case 0:
+ CpuFastCopy(sMenu->frameTiles, dest, TILE_SIZE_4BPP);
+ for (i = 0; i < 6; i++)
+ {
+ CpuFastCopy(sMenu->frameTiles + TILE_SIZE_4BPP, dest + TILE_SIZE_4BPP * (i + 1), TILE_SIZE_4BPP);
+ }
+ CpuFastCopy(sMenu->frameTiles + TILE_SIZE_4BPP * 2, dest + TILE_SIZE_4BPP * 7, TILE_SIZE_4BPP);
+ sMenu->tileLoadState++;
+ break;
+ default:
+ CpuFastCopy(sMenu->frameTiles + TILE_SIZE_4BPP * 3, dest, TILE_SIZE_4BPP);
+ for (i = 0; i < 6; i++)
+ {
+ CpuFastCopy(sMenu->frameTiles + TILE_SIZE_4BPP * 4, dest + TILE_SIZE_4BPP * (i + 1), TILE_SIZE_4BPP);
+ }
+ CpuFastCopy(sMenu->frameTiles + TILE_SIZE_4BPP * 5, dest + TILE_SIZE_4BPP * 7, TILE_SIZE_4BPP);
+ sMenu->tileLoadState++;
+ break;
+ case 13:
+ CpuFastCopy(sMenu->frameTiles + TILE_SIZE_4BPP * 6, dest, TILE_SIZE_4BPP);
+ for (i = 0; i < 6; i++)
+ {
+ CpuFastCopy(sMenu->frameTiles + TILE_SIZE_4BPP * 7, dest + TILE_SIZE_4BPP * (i + 1), TILE_SIZE_4BPP);
+ }
+ CpuFastCopy(sMenu->frameTiles + TILE_SIZE_4BPP * 8, dest + TILE_SIZE_4BPP * 7, TILE_SIZE_4BPP);
+ sMenu->tileLoadState++;
+ return FALSE;
+ case 14:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void sub_811FA90(void)
+{
+ sub_811F918();
+ while (sub_811F960());
+}
+
+void sub_811FAA4(u8 markings, s16 x, s16 y)
+{
+ u16 i;
+ sMenu->cursorPos = 0;
+ sMenu->markings = markings;
+ for (i = 0; i < 4; i++)
+ sMenu->markingsArray[i] = (sMenu->markings >> i) & 1;
+ sub_811FC80(x, y, sMenu->baseTileTag, sMenu->basePaletteTag);
+}
+
+void sub_811FAF8(void)
+{
+ u16 i;
+
+ for (i = 0; i < 2; i++)
+ {
+ FreeSpriteTilesByTag(sMenu->baseTileTag + i);
+ FreeSpritePaletteByTag(sMenu->basePaletteTag + i);
+ }
+ for (i = 0; i < 2; i++)
+ {
+ if (!sMenu->menuWindowSprites[i])
+ return;
+ DestroySprite(sMenu->menuWindowSprites[i]);
+ sMenu->menuWindowSprites[i] = NULL;
+ }
+ for (i = 0; i < 4; i++)
+ {
+ if (!sMenu->menuMarkingSprites[i])
+ return;
+ DestroySprite(sMenu->menuMarkingSprites[i]);
+ sMenu->menuMarkingSprites[i] = NULL;
+ }
+ if (sMenu->unkSprite)
+ {
+ DestroySprite(sMenu->unkSprite);
+ sMenu->unkSprite = NULL;
+ }
+ if (sMenu->menuTextSprite)
+ {
+ DestroySprite(sMenu->menuTextSprite);
+ sMenu->menuTextSprite = NULL;
+ }
+}
+
+
+bool8 sub_811FBA4(void)
+{
+ u16 i;
+
+ if (gMain.newKeys & DPAD_UP)
+ {
+ s8 pos;
+ PlaySE(SE_SELECT);
+ pos = --sMenu->cursorPos;
+ if (pos < 0)
+ sMenu->cursorPos = 5;
+ return TRUE;
+ }
+
+ if (gMain.newKeys & DPAD_DOWN)
+ {
+ s8 pos;
+ PlaySE(SE_SELECT);
+ pos = ++sMenu->cursorPos;
+ if (pos > 5)
+ sMenu->cursorPos = 0;
+ return TRUE;
+ }
+
+ if (gMain.newKeys & A_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+
+ switch (sMenu->cursorPos)
+ {
+ case 4:
+ sMenu->markings = 0;
+ for (i = 0; i < 4; i++)
+ sMenu->markings |= sMenu->markingsArray[i] << i;
+ return FALSE;
+ case 5:
+ return FALSE;
+ }
+
+ sMenu->markingsArray[sMenu->cursorPos] = !sMenu->markingsArray[sMenu->cursorPos];
+ return TRUE;
+ }
+
+ if (gMain.newKeys & B_BUTTON)
+ {
+ PlaySE(SE_SELECT);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void sub_811FC80(s16 x, s16 y, u16 baseTileTag, u16 basePaletteTag)
+{
+ u16 i;
+ u8 spriteId;
+
+ struct SpriteSheet sheets[] =
+ {
+ { sMenu->menuWindowSpriteTiles, 0x1000, baseTileTag },
+ { gPokenavConditionMarker_Gfx, 0x320, baseTileTag + 1 },
+ { NULL, 0 }
+ };
+
+ struct SpritePalette palettes[] =
+ {
+ { sMenu->framePalette, basePaletteTag },
+ { gPokenavConditionMarker_Pal, basePaletteTag + 1},
+ { NULL, 0 }
+ };
+
+ struct SpriteTemplate sprTemplate =
+ {
+ baseTileTag,
+ basePaletteTag,
+ &gUnknown_0859EE7C,
+ gUnknown_0859EF14,
+ NULL,
+ gDummySpriteAffineAnimTable,
+ TaskDummy7,
+ };
+
+ LoadSpriteSheets(sheets);
+ LoadSpritePalettes(palettes);
+
+ for (i = 0; i < 2; i++)
+ {
+ spriteId = CreateSprite(&sprTemplate, x + 32, y + 32, 1);
+ if (spriteId != 64)
+ {
+ sMenu->menuWindowSprites[i] = &gSprites[spriteId];
+ StartSpriteAnim(&gSprites[spriteId], i);
+ }
+ else
+ {
+ sMenu->menuWindowSprites[i] = NULL;
+ return;
+ }
+ }
+
+ sMenu->menuWindowSprites[1]->pos1.y = y + 96;
+
+ sprTemplate.tileTag++;
+ sprTemplate.paletteTag++;
+ sprTemplate.anims = gUnknown_0859EEDC;
+ sprTemplate.callback = sub_811FF40;
+ sprTemplate.oam = &gUnknown_0859EE84;
+
+ for (i = 0; i < 4; i++)
+ {
+ spriteId = CreateSprite(&sprTemplate, x + 32, y + 16 + 16 * i, 0);
+ if (spriteId != 64)
+ {
+ sMenu->menuMarkingSprites[i] = &gSprites[spriteId];
+ gSprites[spriteId].data[0] = i;
+ }
+ else
+ {
+ sMenu->menuMarkingSprites[i] = NULL;
+ return;
+ }
+ }
+
+ sprTemplate.callback = SpriteCallbackDummy;
+
+ spriteId = CreateSprite(&sprTemplate, 0, 0, 0);
+
+ if (spriteId != 64)
+ {
+ sMenu->menuTextSprite = &gSprites[spriteId];
+ sMenu->menuTextSprite->oam.shape = ST_OAM_SQUARE;
+ sMenu->menuTextSprite->oam.size = 2;
+ StartSpriteAnim(sMenu->menuTextSprite, 9);
+ sMenu->menuTextSprite->pos1.x = x + MENU_TEXT_SPRITE_X_OFFSET;
+ sMenu->menuTextSprite->pos1.y = y + 80;
+ CalcCenterToCornerVec(sMenu->menuTextSprite, 1, 2, 0);
+ }
+ else
+ {
+ sMenu->menuTextSprite = NULL;
+ }
+
+ sprTemplate.callback = sub_811FF7C;
+ spriteId = CreateSprite(&sprTemplate, x + 12, 0, 0);
+ if(spriteId != 64)
+ {
+ sMenu->unkSprite = &gSprites[spriteId];
+ sMenu->unkSprite->data[0] = y + 16;
+ StartSpriteAnim(sMenu->unkSprite, 8);
+ }
+ else
+ {
+ sMenu->unkSprite = NULL;
+ }
+
+}
+
+static void TaskDummy7(struct Sprite *sprite)
+{
+}
+
+static void sub_811FF40(struct Sprite *sprite)
+{
+ if (sMenu->markingsArray[sprite->data[0]])
+ StartSpriteAnim(sprite, 2 * sprite->data[0] + 1);
+ else
+ StartSpriteAnim(sprite, 2 * sprite->data[0]);
+}
+
+static void sub_811FF7C(struct Sprite *sprite)
+{
+ sprite->pos1.y = (16 * sMenu->cursorPos) + sprite->data[0];
+}
+
+struct Sprite *sub_811FF94(u16 tileTag, u16 paletteTag, const u16 *palette)
+{
+ if (!palette)
+ palette = gUnknown_0859E65C;
+ return sub_811FFD4(tileTag, paletteTag, palette, 16);
+}
+
+struct Sprite *sub_811FFB4(u16 tileTag, u16 paletteTag, const u16 *palette)
+{
+ if (!palette)
+ palette = gUnknown_0859E65C;
+ return sub_811FFD4(tileTag, paletteTag, palette, 1);
+}
+
+static struct Sprite *sub_811FFD4(u16 tileTag, u16 paletteTag, const u16 *palette, u16 size)
+{
+ u8 spriteId;
+ struct SpriteTemplate sprTemplate;
+ struct SpriteSheet sheet = { gUnknown_0859E67C, 0x80, tileTag };
+ struct SpritePalette sprPalette = { palette, paletteTag };
+
+ sprTemplate.tileTag = tileTag;
+ sprTemplate.paletteTag = paletteTag;
+ sprTemplate.oam = &gUnknown_0859EF1C;
+ sprTemplate.anims = gUnknown_0859EFA4;
+ sprTemplate.images = NULL;
+ sprTemplate.affineAnims = gDummySpriteAffineAnimTable;
+ sprTemplate.callback = TaskDummy7;
+
+ sheet.size = size * 0x80;
+
+ LoadSpriteSheet(&sheet);
+ LoadSpritePalette(&sprPalette);
+
+ spriteId = CreateSprite(&sprTemplate, 0, 0, 0);
+ if (spriteId != 64)
+ return &gSprites[spriteId];
+ else
+ return NULL;
+}
+
+void sub_8120084(u8 markings, void *dest)
+{
+ RequestDma3Copy(gUnknown_0859E67C + markings * 0x80, dest, 0x80, 0x10);
+}
diff --git a/src/overworld.c b/src/overworld.c
index 920f6f8f1..532615f27 100644
--- a/src/overworld.c
+++ b/src/overworld.c
@@ -89,9 +89,6 @@ extern const u16 gUnknown_82EC7C4[];
extern u16 gSaveFileStatus;
extern u16 gUnknown_03005DA8;
-extern u8 *gUnknown_03005DA0;
-extern u8 *gUnknown_03005D9C;
-extern u8 *gUnknown_03005DA4;
extern bool8 (*gUnknown_03005DB0)(void);
extern u8 gUnknown_03005DB4;
extern u8 gFieldLinkPlayerCount;
@@ -1422,12 +1419,12 @@ static void overworld_bg_setup(void)
SetBgAttribute(1, BG_CTRL_ATTR_PALETTEMODE, 1);
SetBgAttribute(2, BG_CTRL_ATTR_PALETTEMODE, 1);
SetBgAttribute(3, BG_CTRL_ATTR_PALETTEMODE, 1);
- gUnknown_03005DA0 = AllocZeroed(0x800);
- gUnknown_03005D9C = AllocZeroed(0x800);
- gUnknown_03005DA4 = AllocZeroed(0x800);
- SetBgTilemapBuffer(1, gUnknown_03005DA0);
- SetBgTilemapBuffer(2, gUnknown_03005D9C);
- SetBgTilemapBuffer(3, gUnknown_03005DA4);
+ gBGTilemapBuffers2 = AllocZeroed(0x800);
+ gBGTilemapBuffers1 = AllocZeroed(0x800);
+ gBGTilemapBuffers3 = AllocZeroed(0x800);
+ SetBgTilemapBuffer(1, gBGTilemapBuffers2);
+ SetBgTilemapBuffer(2, gBGTilemapBuffers1);
+ SetBgTilemapBuffer(3, gBGTilemapBuffers3);
sub_81971D0();
}
@@ -1435,12 +1432,12 @@ void overworld_free_bg_tilemaps(void)
{
sub_81BE72C();
sub_81971F4();
- if (gUnknown_03005DA4 != NULL)
- FREE_AND_SET_NULL(gUnknown_03005DA4);
- if (gUnknown_03005D9C != NULL)
- FREE_AND_SET_NULL(gUnknown_03005D9C);
- if (gUnknown_03005DA0 != NULL)
- FREE_AND_SET_NULL(gUnknown_03005DA0);
+ if (gBGTilemapBuffers3 != NULL)
+ FREE_AND_SET_NULL(gBGTilemapBuffers3);
+ if (gBGTilemapBuffers1 != NULL)
+ FREE_AND_SET_NULL(gBGTilemapBuffers1);
+ if (gBGTilemapBuffers2 != NULL)
+ FREE_AND_SET_NULL(gBGTilemapBuffers2);
}
static void ResetSafariZoneFlag_(void)
diff --git a/src/rotating_gate.c b/src/rotating_gate.c
new file mode 100644
index 000000000..db5935fc3
--- /dev/null
+++ b/src/rotating_gate.c
@@ -0,0 +1,1188 @@
+#include "global.h"
+#include "bike.h"
+#include "event_data.h"
+#include "field_map_obj.h"
+#include "constants/maps.h"
+#include "constants/songs.h"
+#include "sound.h"
+#include "sprite.h"
+
+#define ROTATING_GATE_TILE_TAG 0x1300
+#define ROTATING_GATE_PUZZLE_MAX 12
+#define GATE_ARM_MAX_LENGTH 2
+
+#define GATE_ROT(rotationDirection, arm, longArm) \
+ ((rotationDirection & 15) << 4) | ((arm & 7) << 1) | (longArm & 1)
+#define GATE_ROT_CW(arm, longArm) GATE_ROT(ROTATE_CLOCKWISE, arm, longArm)
+#define GATE_ROT_ACW(arm, longArm) GATE_ROT(ROTATE_ANTICLOCKWISE, arm, longArm)
+#define GATE_ROT_NONE 255
+
+// static functions
+static void SpriteCallback_RotatingGate(struct Sprite *sprite);
+static u8 RotatingGate_CreateGate(u8 gateId, s16 deltaX, s16 deltaY);
+static void RotatingGate_HideGatesOutsideViewport(struct Sprite *sprite);
+
+// enums
+enum
+{
+ /*
+ * |
+ * +--
+ */
+ GATE_SHAPE_L1,
+
+ /*
+ * |
+ * |
+ * +--
+ */
+ GATE_SHAPE_L2,
+
+ /*
+ * |
+ * +----
+ */
+ GATE_SHAPE_L3,
+
+ /*
+ * |
+ * |
+ * +----
+ */
+ GATE_SHAPE_L4,
+
+ /*
+ * |
+ * +--
+ * |
+ */
+ GATE_SHAPE_T1,
+
+ /*
+ * |
+ * |
+ * +--
+ * |
+ */
+ GATE_SHAPE_T2,
+
+ /*
+ * |
+ * +----
+ * |
+ */
+ GATE_SHAPE_T3,
+
+ /*
+ * An unused T-shape gate
+ * |
+ * +--
+ * |
+ * |
+ */
+ GATE_SHAPE_T4,
+
+ /*
+ * An unused T-shape gate
+ * |
+ * |
+ * +----
+ * |
+ */
+ GATE_SHAPE_UNUSED_T1,
+
+ /*
+ * An unused T-shape gate
+ * |
+ * |
+ * +--
+ * |
+ * |
+ */
+ GATE_SHAPE_UNUSED_T2,
+
+ /*
+ * An unused T-shape gate
+ * |
+ * +----
+ * |
+ * |
+ */
+ GATE_SHAPE_UNUSED_T3,
+
+ /*
+ * An unused T-shape gate
+ * |
+ * |
+ * +----
+ * |
+ * |
+ */
+ GATE_SHAPE_UNUSED_T4,
+};
+
+enum
+{
+ /*
+ * 0 degrees (clockwise)
+ * |
+ * +--
+ * |
+ */
+ GATE_ORIENTATION_0,
+
+ /*
+ * 90 degress (clockwise)
+ * --+--
+ * |
+ */
+ GATE_ORIENTATION_90,
+
+ /*
+ * 180 degrees (clockwise)
+ * |
+ * --+
+ * |
+ */
+ GATE_ORIENTATION_180,
+
+ /*
+ * 270 degrees (clockwise)
+ * |
+ * --+--
+ */
+ GATE_ORIENTATION_270,
+
+ GATE_ORIENTATION_MAX,
+};
+
+// Describes the location of the gates "arms" when the gate has not
+// been rotated (i.e. rotated 0 degrees)
+enum
+{
+ GATE_ARM_NORTH,
+ GATE_ARM_EAST,
+ GATE_ARM_SOUTH,
+ GATE_ARM_WEST,
+};
+
+enum
+{
+ ROTATE_NONE,
+ ROTATE_ANTICLOCKWISE,
+ ROTATE_CLOCKWISE,
+};
+
+enum
+{
+ PUZZLE_NONE,
+ PUZZLE_FORTREE_CITY_GYM,
+ PUZZLE_ROUTE110_TRICK_HOUSE_PUZZLE6,
+};
+
+// structure
+struct RotatingGatePuzzle
+{
+ s16 x;
+ s16 y;
+ u8 shape;
+ u8 orientation;
+};
+
+struct Coords8
+{
+ s8 deltaX;
+ s8 deltaY;
+};
+
+// .rodata
+// Fortree
+static const struct RotatingGatePuzzle sRotatingGate_FortreePuzzleConfig[] =
+{
+ { 6, 7, GATE_SHAPE_T2, GATE_ORIENTATION_90},
+ { 9, 15, GATE_SHAPE_T2, GATE_ORIENTATION_180},
+ { 3, 19, GATE_SHAPE_T2, GATE_ORIENTATION_90},
+ { 2, 6, GATE_SHAPE_T1, GATE_ORIENTATION_90},
+ { 9, 12, GATE_SHAPE_T1, GATE_ORIENTATION_0},
+ { 6, 23, GATE_SHAPE_T1, GATE_ORIENTATION_0},
+ {12, 22, GATE_SHAPE_T1, GATE_ORIENTATION_0},
+ { 6, 3, GATE_SHAPE_L4, GATE_ORIENTATION_180},
+};
+
+// Trickhouse
+static const struct RotatingGatePuzzle sRotatingGate_TrickHousePuzzleConfig[] =
+{
+ {14, 5, GATE_SHAPE_T1, GATE_ORIENTATION_90},
+ {10, 6, GATE_SHAPE_L2, GATE_ORIENTATION_180},
+ { 6, 6, GATE_SHAPE_L4, GATE_ORIENTATION_90},
+ {14, 8, GATE_SHAPE_T1, GATE_ORIENTATION_90},
+ { 3, 10, GATE_SHAPE_L3, GATE_ORIENTATION_270},
+ { 9, 14, GATE_SHAPE_L1, GATE_ORIENTATION_90},
+ { 3, 15, GATE_SHAPE_T3, GATE_ORIENTATION_0},
+ { 2, 17, GATE_SHAPE_L2, GATE_ORIENTATION_180},
+ {12, 18, GATE_SHAPE_T3, GATE_ORIENTATION_270},
+ { 5, 18, GATE_SHAPE_L4, GATE_ORIENTATION_90},
+ {10, 19, GATE_SHAPE_L3, GATE_ORIENTATION_180},
+};
+
+static const u8 sRotatingGateTiles_1[] = INCBIN_U8("graphics/misc/rotating_gate_1.4bpp");
+static const u8 sRotatingGateTiles_2[] = INCBIN_U8("graphics/misc/rotating_gate_2.4bpp");
+static const u8 sRotatingGateTiles_3[] = INCBIN_U8("graphics/misc/rotating_gate_3.4bpp");
+static const u8 sRotatingGateTiles_4[] = INCBIN_U8("graphics/misc/rotating_gate_4.4bpp");
+static const u8 sRotatingGateTiles_5[] = INCBIN_U8("graphics/misc/rotating_gate_5.4bpp");
+static const u8 sRotatingGateTiles_6[] = INCBIN_U8("graphics/misc/rotating_gate_6.4bpp");
+static const u8 sRotatingGateTiles_7[] = INCBIN_U8("graphics/misc/rotating_gate_7.4bpp");
+static const u8 sRotatingGateTiles_8[] = INCBIN_U8("graphics/misc/rotating_gate_8.4bpp");
+
+static const struct OamData sOamData_RotatingGateLarge =
+{
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_NORMAL,
+ .objMode = 0,
+ .mosaic = 0,
+ .bpp = ST_OAM_4BPP,
+ .shape = ST_OAM_SQUARE,
+ .x = 0,
+ .matrixNum = 0,
+ .size = 3,
+ .tileNum = 0,
+ .priority = 2,
+ .paletteNum = 2,
+ .affineParam = 0,
+};
+
+static const struct OamData sOamData_RotatingGateRegular =
+{
+ .y = 0,
+ .affineMode = ST_OAM_AFFINE_NORMAL,
+ .objMode = 0,
+ .mosaic = 0,
+ .bpp = ST_OAM_4BPP,
+ .shape = ST_OAM_SQUARE,
+ .x = 0,
+ .matrixNum = 0,
+ .size = 2,
+ .tileNum = 0,
+ .priority = 2,
+ .paletteNum = 2,
+ .affineParam = 0,
+};
+
+static const struct SpriteSheet sRotatingGatesGraphicsTable[] =
+{
+ {sRotatingGateTiles_1, 0x200, ROTATING_GATE_TILE_TAG + GATE_SHAPE_L1},
+ {sRotatingGateTiles_2, 0x800, ROTATING_GATE_TILE_TAG + GATE_SHAPE_L2},
+ {sRotatingGateTiles_3, 0x800, ROTATING_GATE_TILE_TAG + GATE_SHAPE_L3},
+ {sRotatingGateTiles_4, 0x800, ROTATING_GATE_TILE_TAG + GATE_SHAPE_L4},
+ {sRotatingGateTiles_5, 0x200, ROTATING_GATE_TILE_TAG + GATE_SHAPE_T1},
+ {sRotatingGateTiles_6, 0x800, ROTATING_GATE_TILE_TAG + GATE_SHAPE_T2},
+ {sRotatingGateTiles_7, 0x800, ROTATING_GATE_TILE_TAG + GATE_SHAPE_T3},
+ {sRotatingGateTiles_8, 0x800, ROTATING_GATE_TILE_TAG + GATE_SHAPE_T4},
+ {NULL},
+};
+
+static const union AnimCmd sSpriteAnim_RotatingGateLarge[] =
+{
+ ANIMCMD_FRAME(0, 0),
+ ANIMCMD_END,
+};
+
+static const union AnimCmd sSpriteAnim_RotatingGateRegular[] =
+{
+ ANIMCMD_FRAME(0, 0), ANIMCMD_END,
+};
+
+static const union AnimCmd *const sSpriteAnimTable_RotatingGateLarge[] =
+{
+ sSpriteAnim_RotatingGateLarge,
+};
+
+static const union AnimCmd *const sSpriteAnimTable_RotatingGateRegular[] =
+{
+ sSpriteAnim_RotatingGateRegular,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_Rotated0[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_Rotated90[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -64, 0),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_Rotated180[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -128, 0),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_Rotated270[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 64, 0),
+ AFFINEANIMCMD_JUMP(0),
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingClockwise0to90[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -4, 16),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingClockwise90to180[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -64, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -4, 16),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingClockwise180to270[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -128, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -4, 16),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingClockwise270to360[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 64, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -4, 16),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingAnticlockwise360to270[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 4, 16),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingAnticlockwise270to180[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 64, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 4, 16),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingAnticlockwise180to90[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -128, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 4, 16),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingAnticlockwise90to0[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -64, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 4, 16),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingClockwise0to90Faster[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -8, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingClockwise90to180Faster[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -64, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -8, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingClockwise180to270Faster[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -128, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -8, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingClockwise270to360Faster[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 64, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, -8, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingAnticlockwise360to270Faster[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 0, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 8, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingAnticlockwise270to180Faster[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, 64, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 8, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingAnticlockwise180to90Faster[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -128, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 8, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd sSpriteAffineAnim_RotatingAnticlockwise90to0Faster[] =
+{
+ AFFINEANIMCMD_FRAME(0x100, 0x100, -64, 0),
+ AFFINEANIMCMD_FRAME(0x0, 0x0, 8, 8),
+ AFFINEANIMCMD_END,
+};
+
+static const union AffineAnimCmd *const sSpriteAffineAnimTable_RotatingGate[] =
+{
+ sSpriteAffineAnim_Rotated0,
+ sSpriteAffineAnim_Rotated90,
+ sSpriteAffineAnim_Rotated180,
+ sSpriteAffineAnim_Rotated270,
+ sSpriteAffineAnim_RotatingAnticlockwise360to270,
+ sSpriteAffineAnim_RotatingAnticlockwise90to0,
+ sSpriteAffineAnim_RotatingAnticlockwise180to90,
+ sSpriteAffineAnim_RotatingAnticlockwise270to180,
+ sSpriteAffineAnim_RotatingClockwise0to90,
+ sSpriteAffineAnim_RotatingClockwise90to180,
+ sSpriteAffineAnim_RotatingClockwise180to270,
+ sSpriteAffineAnim_RotatingClockwise270to360,
+ sSpriteAffineAnim_RotatingAnticlockwise360to270Faster,
+ sSpriteAffineAnim_RotatingAnticlockwise90to0Faster,
+ sSpriteAffineAnim_RotatingAnticlockwise180to90Faster,
+ sSpriteAffineAnim_RotatingAnticlockwise270to180Faster,
+ sSpriteAffineAnim_RotatingClockwise0to90Faster,
+ sSpriteAffineAnim_RotatingClockwise90to180Faster,
+ sSpriteAffineAnim_RotatingClockwise180to270Faster,
+ sSpriteAffineAnim_RotatingClockwise270to360Faster,
+};
+
+
+static const struct SpriteTemplate sSpriteTemplate_RotatingGateLarge =
+{
+ .tileTag = ROTATING_GATE_TILE_TAG,
+ .paletteTag = 0xFFFF,
+ .oam = &sOamData_RotatingGateLarge,
+ .anims = sSpriteAnimTable_RotatingGateLarge,
+ .images = NULL,
+ .affineAnims = sSpriteAffineAnimTable_RotatingGate,
+ .callback = SpriteCallback_RotatingGate,
+};
+
+static const struct SpriteTemplate sSpriteTemplate_RotatingGateRegular =
+{
+ .tileTag = ROTATING_GATE_TILE_TAG,
+ .paletteTag = 0xFFFF,
+ .oam = &sOamData_RotatingGateRegular,
+ .anims = sSpriteAnimTable_RotatingGateRegular,
+ .images = NULL,
+ .affineAnims = sSpriteAffineAnimTable_RotatingGate,
+ .callback = SpriteCallback_RotatingGate,
+};
+
+// These structures describe what happens to the gate if you hit it at
+// a given coordinate in a 4x4 grid when walking in the specified
+// direction. Either the gate does not rotate, or it rotates in the
+// given direction. This information is compared against the gate
+// "arm" layout to see if there is an arm at the position in order to
+// produce the final rotation.
+static const u8 sRotatingGate_RotationInfoNorth[4 * 4] =
+{
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE,
+ GATE_ROT_CW(GATE_ARM_WEST, 1), GATE_ROT_CW(GATE_ARM_WEST, 0), GATE_ROT_ACW(GATE_ARM_EAST, 0), GATE_ROT_ACW(GATE_ARM_EAST, 1),
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE,
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE,
+};
+
+static const u8 sRotatingGate_RotationInfoSouth[4 * 4] =
+{
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE,
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE,
+ GATE_ROT_ACW(GATE_ARM_WEST, 1), GATE_ROT_ACW(GATE_ARM_WEST, 0), GATE_ROT_CW(GATE_ARM_EAST, 0), GATE_ROT_CW(GATE_ARM_EAST, 1),
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_NONE,
+};
+
+static const u8 sRotatingGate_RotationInfoWest[4 * 4] =
+{
+ GATE_ROT_NONE, GATE_ROT_ACW(GATE_ARM_NORTH, 1), GATE_ROT_NONE, GATE_ROT_NONE,
+ GATE_ROT_NONE, GATE_ROT_ACW(GATE_ARM_NORTH, 0), GATE_ROT_NONE, GATE_ROT_NONE,
+ GATE_ROT_NONE, GATE_ROT_CW(GATE_ARM_SOUTH, 0), GATE_ROT_NONE, GATE_ROT_NONE,
+ GATE_ROT_NONE, GATE_ROT_CW(GATE_ARM_SOUTH, 1), GATE_ROT_NONE, GATE_ROT_NONE,
+};
+
+static const u8 sRotatingGate_RotationInfoEast[4 * 4] =
+{
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_CW(GATE_ARM_NORTH, 1), GATE_ROT_NONE,
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_CW(GATE_ARM_NORTH, 0), GATE_ROT_NONE,
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_ACW(GATE_ARM_SOUTH, 0), GATE_ROT_NONE,
+ GATE_ROT_NONE, GATE_ROT_NONE, GATE_ROT_ACW(GATE_ARM_SOUTH, 1), GATE_ROT_NONE,
+};
+
+// These tables describe the relative coordinate positions the arms
+// must move through in order to be rotated.
+static const struct Coords8 sRotatingGate_ArmPositionsClockwiseRotation[] = {
+ { 0, -1 }, { 1, -2 }, { 0, 0 }, { 1, 0 }, { -1, 0 }, { -1, 1 }, { -1, -1 }, { -2, -1 },
+};
+
+static const struct Coords8 sRotatingGate_ArmPositionsAntiClockwiseRotation[] = {
+ { -1, -1 }, { -1, -2 }, { 0, -1 }, { 1, -1 }, { 0, 0 }, { 0, 1 }, { -1, 0 }, { -2, 0 },
+};
+
+// Describes where the gates "arms" are in the order north, east, south, west.
+// These are adjusted using the current orientation to perform collision checking
+static const u8 sRotatingGate_ArmLayout[][4 * 2] =
+{
+ // L-shape gates
+ {
+ 1, 0,
+ 1, 0,
+ 0, 0,
+ 0, 0,
+ },
+ {
+ 1, 1,
+ 1, 0,
+ 0, 0,
+ 0, 0,
+ },
+ {
+ 1, 0,
+ 1, 1,
+ 0, 0,
+ 0, 0,
+ },
+ {
+ 1, 1,
+ 1, 1,
+ 0, 0,
+ 0, 0,
+ },
+
+ // T-shape gates
+ {
+ 1, 0,
+ 1, 0,
+ 1, 0,
+ 0, 0,
+ },
+ {
+ 1, 1,
+ 1, 0,
+ 1, 0,
+ 0, 0,
+ },
+ {
+ 1, 0,
+ 1, 1,
+ 1, 0,
+ 0, 0,
+ },
+ {
+ 1, 0,
+ 1, 0,
+ 1, 1,
+ 0, 0,
+ },
+
+ // Unused T-shape gates
+ // These have 2-3 long arms and cannot actually be used anywhere
+ // since configuration for them is missing from the other tables.
+ {
+ 1, 1,
+ 1, 1,
+ 1, 0,
+ 0, 0,
+ },
+ {
+ 1, 1,
+ 1, 0,
+ 1, 1,
+ 0, 0,
+ },
+ {
+ 1, 0,
+ 1, 1,
+ 1, 1,
+ 0, 0,
+ },
+ {
+ 1, 1,
+ 1, 1,
+ 1, 1,
+ 0, 0,
+ },
+};
+
+// ewram
+static EWRAM_DATA u8 gRotatingGate_GateSpriteIds[ROTATING_GATE_PUZZLE_MAX] = {0};
+static EWRAM_DATA const struct RotatingGatePuzzle *gRotatingGate_PuzzleConfig = NULL;
+static EWRAM_DATA u8 gRotatingGate_PuzzleCount = 0;
+
+// text
+static s32 GetCurrentMapRotatingGatePuzzleType(void)
+{
+ if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(FORTREE_CITY_GYM) &&
+ gSaveBlock1Ptr->location.mapNum == MAP_NUM(FORTREE_CITY_GYM))
+ {
+ return PUZZLE_FORTREE_CITY_GYM;
+ }
+
+ if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(ROUTE110_TRICK_HOUSE_PUZZLE6) &&
+ gSaveBlock1Ptr->location.mapNum == MAP_NUM(ROUTE110_TRICK_HOUSE_PUZZLE6))
+ {
+ return PUZZLE_ROUTE110_TRICK_HOUSE_PUZZLE6;
+ }
+
+ return PUZZLE_NONE;
+}
+
+static void RotatingGate_ResetAllGateOrientations(void)
+{
+ s32 i;
+ u8 *ptr;
+
+ ptr = (u8 *)GetVarPointer(VAR_0x4000);
+
+ for (i = 0; i < gRotatingGate_PuzzleCount; i++)
+ {
+ ptr[i] = gRotatingGate_PuzzleConfig[i].orientation;
+ }
+}
+
+static s32 RotatingGate_GetGateOrientation(u8 gateId)
+{
+ return ((u8 *)GetVarPointer(VAR_0x4000))[gateId];
+}
+
+static void RotatingGate_SetGateOrientation(u8 gateId, u8 orientation)
+{
+ ((u8 *)GetVarPointer(VAR_0x4000))[gateId] = orientation;
+}
+
+static void RotatingGate_RotateInDirection(u8 gateId, u32 rotationDirection)
+{
+ u8 orientation = RotatingGate_GetGateOrientation(gateId);
+
+ if (rotationDirection == ROTATE_ANTICLOCKWISE)
+ {
+ if (orientation)
+ orientation--;
+ else
+ orientation = GATE_ORIENTATION_270;
+ }
+ else
+ {
+ orientation = ++orientation % GATE_ORIENTATION_MAX;
+ }
+ RotatingGate_SetGateOrientation(gateId, orientation);
+}
+
+static void RotatingGate_LoadPuzzleConfig(void)
+{
+ s32 puzzleType = GetCurrentMapRotatingGatePuzzleType();
+ u32 i;
+
+ switch (puzzleType)
+ {
+ case PUZZLE_FORTREE_CITY_GYM:
+ gRotatingGate_PuzzleConfig = sRotatingGate_FortreePuzzleConfig;
+ gRotatingGate_PuzzleCount =
+ sizeof(sRotatingGate_FortreePuzzleConfig) / sizeof(struct RotatingGatePuzzle);
+ break;
+ case PUZZLE_ROUTE110_TRICK_HOUSE_PUZZLE6:
+ gRotatingGate_PuzzleConfig = sRotatingGate_TrickHousePuzzleConfig;
+ gRotatingGate_PuzzleCount =
+ sizeof(sRotatingGate_TrickHousePuzzleConfig) / sizeof(struct RotatingGatePuzzle);
+ break;
+ case PUZZLE_NONE:
+ default:
+ return;
+ }
+
+ for (i = 0; i < ROTATING_GATE_PUZZLE_MAX - 1; i++)
+ {
+ gRotatingGate_GateSpriteIds[i] = MAX_SPRITES;
+ }
+}
+
+static void RotatingGate_CreateGatesWithinViewport(s16 deltaX, s16 deltaY)
+{
+ u8 i;
+
+ // Calculate the bounding box of the camera
+ // Same as RotatingGate_DestroyGatesOutsideViewport
+ s16 x = gSaveBlock1Ptr->pos.x - 2;
+ s16 x2 = gSaveBlock1Ptr->pos.x + 0x11;
+ s16 y = gSaveBlock1Ptr->pos.y - 2;
+ s16 y2 = gSaveBlock1Ptr->pos.y + 0xe;
+
+ s16 x3, y3;
+
+ for (i = 0; i < gRotatingGate_PuzzleCount; i++)
+ {
+ x3 = gRotatingGate_PuzzleConfig[i].x + 7;
+ y3 = gRotatingGate_PuzzleConfig[i].y + 7;
+
+ if (y <= y3 && y2 >= y3 && x <= x3 && x2 >= x3 &&
+ gRotatingGate_GateSpriteIds[i] == MAX_SPRITES)
+ {
+ gRotatingGate_GateSpriteIds[i] = RotatingGate_CreateGate(i, deltaX, deltaY);
+ }
+ }
+}
+
+static u8 RotatingGate_CreateGate(u8 gateId, s16 deltaX, s16 deltaY)
+{
+ struct Sprite *sprite;
+ struct SpriteTemplate template;
+ const struct RotatingGatePuzzle *gate;
+ u8 spriteId;
+ s16 x, y;
+
+ gate = &gRotatingGate_PuzzleConfig[gateId];
+
+ if (gate->shape == GATE_SHAPE_L1 || gate->shape == GATE_SHAPE_T1)
+ template = sSpriteTemplate_RotatingGateRegular;
+ else
+ template = sSpriteTemplate_RotatingGateLarge;
+
+ template.tileTag = gate->shape + ROTATING_GATE_TILE_TAG;
+
+ spriteId = CreateSprite(&template, 0, 0, 0x94);
+ if (spriteId == MAX_SPRITES)
+ return MAX_SPRITES;
+
+ x = gate->x + 7;
+ y = gate->y + 7;
+
+ sprite = &gSprites[spriteId];
+ sprite->data[0] = gateId;
+ sprite->coordOffsetEnabled = 1;
+
+ sub_8092FF0(x + deltaX, y + deltaY, &sprite->pos1.x, &sprite->pos1.y);
+ RotatingGate_HideGatesOutsideViewport(sprite);
+ StartSpriteAffineAnim(sprite, RotatingGate_GetGateOrientation(gateId));
+
+ return spriteId;
+}
+
+static void SpriteCallback_RotatingGate(struct Sprite *sprite)
+{
+ u8 rotationDirection;
+ u8 orientation;
+ u8 affineAnimation;
+
+ rotationDirection = sprite->data[1];
+ orientation = sprite->data[2];
+
+ RotatingGate_HideGatesOutsideViewport(sprite);
+
+ if (rotationDirection == ROTATE_ANTICLOCKWISE)
+ {
+ affineAnimation = orientation + 4;
+
+ if (GetPlayerSpeed() != 1)
+ affineAnimation += 8;
+
+ PlaySE(SE_HI_TURUN);
+ StartSpriteAffineAnim(sprite, affineAnimation);
+ }
+ else if (rotationDirection == ROTATE_CLOCKWISE)
+ {
+ affineAnimation = orientation + 8;
+
+ if (GetPlayerSpeed() != 1)
+ affineAnimation += 8;
+
+ PlaySE(SE_HI_TURUN);
+ StartSpriteAffineAnim(sprite, affineAnimation);
+ }
+
+ sprite->data[1] = ROTATE_NONE;
+}
+
+static void RotatingGate_HideGatesOutsideViewport(struct Sprite *sprite)
+{
+ u16 x;
+ s16 x2;
+ u16 y;
+ s16 y2;
+
+ sprite->invisible = FALSE;
+ x = sprite->pos1.x + sprite->pos2.x + sprite->centerToCornerVecX + gSpriteCoordOffsetX;
+ y = sprite->pos1.y + sprite->pos2.y + sprite->centerToCornerVecY + gSpriteCoordOffsetY;
+
+ x2 = x + 0x40; // Dimensions of the rotating gate
+ y2 = y + 0x40;
+
+ if ((s16)x > DISPLAY_WIDTH + 0x10 - 1 || x2 < -0x10)
+ {
+ sprite->invisible = TRUE;
+ }
+
+ if ((s16)y > DISPLAY_HEIGHT + 0x10 - 1 || y2 < -0x10)
+ {
+ sprite->invisible = TRUE;
+ }
+}
+
+static void LoadRotatingGatePics(void)
+{
+ LoadSpriteSheets(sRotatingGatesGraphicsTable);
+}
+
+/*
+static*/ void RotatingGate_DestroyGatesOutsideViewport(void)
+{
+ s16 x;
+ s16 x2;
+ s16 y;
+ s16 y2;
+ s16 xGate;
+ s16 yGate;
+ s32 i;
+ struct Sprite *sprite;
+
+ // Same as RotatingGate_CreateGatesWithinViewport
+ x = gSaveBlock1Ptr->pos.x - 2;
+ x2 = gSaveBlock1Ptr->pos.x + 0x11;
+ y = gSaveBlock1Ptr->pos.y - 2;
+ y2 = gSaveBlock1Ptr->pos.y + 0xe;
+
+ for (i = 0; i < gRotatingGate_PuzzleCount; i++)
+ {
+ xGate = gRotatingGate_PuzzleConfig[i].x + 7;
+ yGate = gRotatingGate_PuzzleConfig[i].y + 7;
+
+ if (gRotatingGate_GateSpriteIds[i] == MAX_SPRITES)
+ continue;
+
+ if (xGate < x || xGate > x2 || yGate < y || yGate > y2)
+ {
+ sprite = &gSprites[gRotatingGate_GateSpriteIds[i]];
+ FreeSpriteOamMatrix(sprite);
+ DestroySprite(sprite);
+ gRotatingGate_GateSpriteIds[i] = MAX_SPRITES;
+ }
+ }
+}
+
+
+#ifdef NONMATCHING
+bool8 MapGridIsImpassableAt(s32, s32); //fool the compiler
+
+static s32 RotatingGate_CanRotate(u8 gateId, s16 rotationDirection)
+{
+ const struct Coords8 *armPos;
+ u8 orientation;
+ s16 x;
+ s16 y;
+ u8 shape;
+ u32 shape8;
+ s32 i;
+ s32 j;
+ s32 armOrientation;
+ const u8 *gateArmCollisionData;
+ u8 armIndex;
+
+ if (rotationDirection == ROTATE_ANTICLOCKWISE)
+ armPos = sRotatingGate_ArmPositionsAntiClockwiseRotation;
+ else if (rotationDirection == ROTATE_CLOCKWISE)
+ armPos = sRotatingGate_ArmPositionsClockwiseRotation;
+ else
+ return FALSE;
+
+ orientation = RotatingGate_GetGateOrientation(gateId);
+
+ shape = gRotatingGate_PuzzleConfig[gateId].shape;
+ x = gRotatingGate_PuzzleConfig[gateId].x + 7;
+ y = gRotatingGate_PuzzleConfig[gateId].y + 7;
+
+
+ // Loop through the gate's "arms" clockwise (north, south, east, west)
+ for (i = GATE_ARM_NORTH, shape8 = shape* 4*2 ; i <= GATE_ARM_WEST; i++)
+ {
+ // Ensure that no part of the arm collides with the map
+ for (j = 0, armOrientation = orientation + i, gateArmCollisionData = (u8 *)((u32)sRotatingGate_ArmLayout + shape8 + 2*i); j < GATE_ARM_MAX_LENGTH; j++)
+ {
+ armIndex = 2 * (armOrientation % 4) + j;
+
+ if (*gateArmCollisionData)
+ {
+ if (MapGridIsImpassableAt(x + armPos[armIndex].deltaX, y + armPos[armIndex].deltaY) == TRUE)
+ return FALSE;
+ }
+ gateArmCollisionData++;
+ }
+ }
+
+ return TRUE;
+}
+
+#else
+ASM_DIRECT
+static s32 RotatingGate_CanRotate(u8 a, s16 rotationDirection)
+{
+ asm(".syntax unified\n\
+ push {r4-r7,lr}\n\
+ mov r7, r10\n\
+ mov r6, r9\n\
+ mov r5, r8\n\
+ push {r5-r7}\n\
+ sub sp, 0xC\n\
+ lsls r0, 24\n\
+ lsrs r4, r0, 24\n\
+ cmp r1, 0x1\n\
+ bne _080FBCFC\n\
+ ldr r0, =sRotatingGate_ArmPositionsAntiClockwiseRotation\n\
+ mov r10, r0\n\
+ b _080FBD08\n\
+ .pool\n\
+_080FBCFC:\n\
+ cmp r1, 0x2\n\
+ beq _080FBD04\n\
+_080FBD00:\n\
+ movs r0, 0\n\
+ b _080FBD98\n\
+_080FBD04:\n\
+ ldr r1, =sRotatingGate_ArmPositionsClockwiseRotation\n\
+ mov r10, r1\n\
+_080FBD08:\n\
+ adds r0, r4, 0\n\
+ bl RotatingGate_GetGateOrientation\n\
+ lsls r0, 24\n\
+ lsrs r0, 24\n\
+ str r0, [sp]\n\
+ ldr r0, =gRotatingGate_PuzzleConfig\n\
+ ldr r1, [r0]\n\
+ lsls r0, r4, 3\n\
+ adds r0, r1\n\
+ ldrb r2, [r0, 0x4]\n\
+ ldrh r1, [r0]\n\
+ adds r1, 0x7\n\
+ ldrh r0, [r0, 0x2]\n\
+ adds r0, 0x7\n\
+ movs r3, 0\n\
+ lsls r2, 3\n\
+ str r2, [sp, 0x4]\n\
+ lsls r1, 16\n\
+ asrs r1, 16\n\
+ mov r9, r1\n\
+ lsls r0, 16\n\
+ asrs r0, 16\n\
+ mov r8, r0\n\
+_080FBD38:\n\
+ movs r6, 0\n\
+ ldr r2, [sp]\n\
+ adds r7, r2, r3\n\
+ lsls r0, r3, 1\n\
+ adds r5, r7, 0\n\
+ ldr r1, [sp, 0x4]\n\
+ adds r0, r1\n\
+ ldr r2, =sRotatingGate_ArmLayout\n\
+ adds r4, r0, r2\n\
+_080FBD4A:\n\
+ adds r0, r5, 0\n\
+ cmp r5, 0\n\
+ bge _080FBD52\n\
+ adds r0, r7, 0x3\n\
+_080FBD52:\n\
+ asrs r0, 2\n\
+ lsls r0, 2\n\
+ subs r0, r5, r0\n\
+ lsls r0, 1\n\
+ adds r0, r6\n\
+ lsls r0, 24\n\
+ lsrs r1, r0, 24\n\
+ ldrb r0, [r4]\n\
+ cmp r0, 0\n\
+ beq _080FBD88\n\
+ lsls r1, 2\n\
+ add r1, r10\n\
+ movs r0, 0\n\
+ ldrsb r0, [r1, r0]\n\
+ add r0, r9\n\
+ ldrb r1, [r1, 0x1]\n\
+ lsls r1, 24\n\
+ asrs r1, 24\n\
+ add r1, r8\n\
+ str r3, [sp, 0x8]\n\
+ bl MapGridIsImpassableAt\n\
+ lsls r0, 24\n\
+ lsrs r0, 24\n\
+ ldr r3, [sp, 0x8]\n\
+ cmp r0, 0x1\n\
+ beq _080FBD00\n\
+_080FBD88:\n\
+ adds r4, 0x1\n\
+ adds r6, 0x1\n\
+ cmp r6, 0x1\n\
+ ble _080FBD4A\n\
+ adds r3, 0x1\n\
+ cmp r3, 0x3\n\
+ ble _080FBD38\n\
+ movs r0, 0x1\n\
+_080FBD98:\n\
+ add sp, 0xC\n\
+ pop {r3-r5}\n\
+ mov r8, r3\n\
+ mov r9, r4\n\
+ mov r10, r5\n\
+ pop {r4-r7}\n\
+ pop {r1}\n\
+ bx r1\n\
+ .pool\n\
+.syntax divided\n");
+}
+#endif
+
+static s32 RotatingGate_HasArm(u8 gateId, u8 armInfo)
+{
+ s32 isLongArm;
+ s8 armOrientation;
+ s32 arm;
+ s32 shape;
+
+ arm = armInfo >> 1;
+ isLongArm = armInfo & 1;
+
+ armOrientation = (arm - RotatingGate_GetGateOrientation(gateId) + 4) % 4;
+ shape = gRotatingGate_PuzzleConfig[gateId].shape;
+ return sRotatingGate_ArmLayout[shape][armOrientation * 2 + isLongArm];
+}
+
+static void RotatingGate_TriggerRotationAnimation(u8 gateId, s32 rotationDirection)
+{
+ struct Sprite *sprite;
+
+ if (gRotatingGate_GateSpriteIds[gateId] != MAX_SPRITES)
+ {
+ sprite = &gSprites[gRotatingGate_GateSpriteIds[gateId]];
+ sprite->data[1] = rotationDirection;
+ sprite->data[2] = RotatingGate_GetGateOrientation(gateId);
+ }
+}
+
+static u8 RotatingGate_GetRotationInfo(u8 direction, s16 x, s16 y)
+{
+ register const u8 *ptr;
+
+ if (direction == DIR_NORTH)
+ ptr = sRotatingGate_RotationInfoNorth;
+ else if (direction == DIR_SOUTH)
+ ptr = sRotatingGate_RotationInfoSouth;
+ else if (direction == DIR_WEST)
+ ptr = sRotatingGate_RotationInfoWest;
+ else if (direction == DIR_EAST)
+ ptr = sRotatingGate_RotationInfoEast;
+ else
+ return GATE_ROT_NONE;
+
+ return ptr[y * 4 + x];
+}
+
+void RotatingGate_InitPuzzle(void)
+{
+ if (GetCurrentMapRotatingGatePuzzleType())
+ {
+ RotatingGate_LoadPuzzleConfig();
+ RotatingGate_ResetAllGateOrientations();
+ }
+}
+
+void RotatingGatePuzzleCameraUpdate(u16 deltaX, u16 deltaY)
+{
+ if (GetCurrentMapRotatingGatePuzzleType())
+ {
+ RotatingGate_CreateGatesWithinViewport(deltaX, deltaY);
+ RotatingGate_DestroyGatesOutsideViewport();
+ }
+}
+
+void RotatingGate_InitPuzzleAndGraphics(void)
+{
+ if (GetCurrentMapRotatingGatePuzzleType())
+ {
+ LoadRotatingGatePics();
+ RotatingGate_LoadPuzzleConfig();
+ RotatingGate_CreateGatesWithinViewport(0, 0);
+ }
+}
+
+bool8 CheckForRotatingGatePuzzleCollision(u8 direction, s16 x, s16 y)
+{
+ s32 i;
+
+ if (!GetCurrentMapRotatingGatePuzzleType())
+ return FALSE;
+ for (i = 0; i < gRotatingGate_PuzzleCount; i++)
+ {
+ s16 gateX = gRotatingGate_PuzzleConfig[i].x + 7;
+ s16 gateY = gRotatingGate_PuzzleConfig[i].y + 7;
+
+ if (gateX - 2 <= x && x <= gateX + 1 && gateY - 2 <= y && y <= gateY + 1)
+ {
+ s16 centerX = x - gateX + 2;
+ s16 centerY = y - gateY + 2;
+ u8 rotationInfo = RotatingGate_GetRotationInfo(direction, centerX, centerY);
+
+ if (rotationInfo != GATE_ROT_NONE)
+ {
+ u8 rotationDirection = ((rotationInfo & 0xF0) >> 4);
+ u8 armInfo = rotationInfo & 0xF;
+
+ if (RotatingGate_HasArm(i, armInfo))
+ {
+ if (RotatingGate_CanRotate(i, rotationDirection))
+ {
+ RotatingGate_TriggerRotationAnimation(i, rotationDirection);
+ RotatingGate_RotateInDirection(i, rotationDirection);
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+bool8 CheckForRotatingGatePuzzleCollisionWithoutAnimation(u8 direction, s16 x, s16 y)
+{
+ s32 i;
+
+ if (!GetCurrentMapRotatingGatePuzzleType())
+ return FALSE;
+ for (i = 0; i < gRotatingGate_PuzzleCount; i++)
+ {
+ s16 gateX = gRotatingGate_PuzzleConfig[i].x + 7;
+ s16 gateY = gRotatingGate_PuzzleConfig[i].y + 7;
+
+ if (gateX - 2 <= x && x <= gateX + 1 && gateY - 2 <= y && y <= gateY + 1)
+ {
+ s16 centerX = x - gateX + 2;
+ s16 centerY = y - gateY + 2;
+ u8 rotationInfo = RotatingGate_GetRotationInfo(direction, centerX, centerY);
+
+ if (rotationInfo != GATE_ROT_NONE)
+ {
+ u8 rotationDirection = ((rotationInfo & 0xF0) >> 4);
+ u8 armInfo = rotationInfo & 0xF;
+
+ if (RotatingGate_HasArm(i, armInfo))
+ {
+ if (!RotatingGate_CanRotate(i, rotationDirection))
+ {
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ return FALSE;
+}
diff --git a/src/text_window.c b/src/text_window.c
index 33cd7cffe..c3b9f7197 100644
--- a/src/text_window.c
+++ b/src/text_window.c
@@ -7,26 +7,26 @@
#include "graphics.h"
// const rom data
-const u32 gTextWindowFrame1_Gfx[] = INCBIN_U32("graphics/text_window/1.4bpp");
-static const u32 sTextWindowFrame2_Gfx[] = INCBIN_U32("graphics/text_window/2.4bpp");
-static const u32 sTextWindowFrame3_Gfx[] = INCBIN_U32("graphics/text_window/3.4bpp");
-static const u32 sTextWindowFrame4_Gfx[] = INCBIN_U32("graphics/text_window/4.4bpp");
-static const u32 sTextWindowFrame5_Gfx[] = INCBIN_U32("graphics/text_window/5.4bpp");
-static const u32 sTextWindowFrame6_Gfx[] = INCBIN_U32("graphics/text_window/6.4bpp");
-static const u32 sTextWindowFrame7_Gfx[] = INCBIN_U32("graphics/text_window/7.4bpp");
-static const u32 sTextWindowFrame8_Gfx[] = INCBIN_U32("graphics/text_window/8.4bpp");
-static const u32 sTextWindowFrame9_Gfx[] = INCBIN_U32("graphics/text_window/9.4bpp");
-static const u32 sTextWindowFrame10_Gfx[] = INCBIN_U32("graphics/text_window/10.4bpp");
-static const u32 sTextWindowFrame11_Gfx[] = INCBIN_U32("graphics/text_window/11.4bpp");
-static const u32 sTextWindowFrame12_Gfx[] = INCBIN_U32("graphics/text_window/12.4bpp");
-static const u32 sTextWindowFrame13_Gfx[] = INCBIN_U32("graphics/text_window/13.4bpp");
-static const u32 sTextWindowFrame14_Gfx[] = INCBIN_U32("graphics/text_window/14.4bpp");
-static const u32 sTextWindowFrame15_Gfx[] = INCBIN_U32("graphics/text_window/15.4bpp");
-static const u32 sTextWindowFrame16_Gfx[] = INCBIN_U32("graphics/text_window/16.4bpp");
-static const u32 sTextWindowFrame17_Gfx[] = INCBIN_U32("graphics/text_window/17.4bpp");
-static const u32 sTextWindowFrame18_Gfx[] = INCBIN_U32("graphics/text_window/18.4bpp");
-static const u32 sTextWindowFrame19_Gfx[] = INCBIN_U32("graphics/text_window/19.4bpp");
-static const u32 sTextWindowFrame20_Gfx[] = INCBIN_U32("graphics/text_window/20.4bpp");
+const u8 gTextWindowFrame1_Gfx[] = INCBIN_U8("graphics/text_window/1.4bpp");
+static const u8 sTextWindowFrame2_Gfx[] = INCBIN_U8("graphics/text_window/2.4bpp");
+static const u8 sTextWindowFrame3_Gfx[] = INCBIN_U8("graphics/text_window/3.4bpp");
+static const u8 sTextWindowFrame4_Gfx[] = INCBIN_U8("graphics/text_window/4.4bpp");
+static const u8 sTextWindowFrame5_Gfx[] = INCBIN_U8("graphics/text_window/5.4bpp");
+static const u8 sTextWindowFrame6_Gfx[] = INCBIN_U8("graphics/text_window/6.4bpp");
+static const u8 sTextWindowFrame7_Gfx[] = INCBIN_U8("graphics/text_window/7.4bpp");
+static const u8 sTextWindowFrame8_Gfx[] = INCBIN_U8("graphics/text_window/8.4bpp");
+static const u8 sTextWindowFrame9_Gfx[] = INCBIN_U8("graphics/text_window/9.4bpp");
+static const u8 sTextWindowFrame10_Gfx[] = INCBIN_U8("graphics/text_window/10.4bpp");
+static const u8 sTextWindowFrame11_Gfx[] = INCBIN_U8("graphics/text_window/11.4bpp");
+static const u8 sTextWindowFrame12_Gfx[] = INCBIN_U8("graphics/text_window/12.4bpp");
+static const u8 sTextWindowFrame13_Gfx[] = INCBIN_U8("graphics/text_window/13.4bpp");
+static const u8 sTextWindowFrame14_Gfx[] = INCBIN_U8("graphics/text_window/14.4bpp");
+static const u8 sTextWindowFrame15_Gfx[] = INCBIN_U8("graphics/text_window/15.4bpp");
+static const u8 sTextWindowFrame16_Gfx[] = INCBIN_U8("graphics/text_window/16.4bpp");
+static const u8 sTextWindowFrame17_Gfx[] = INCBIN_U8("graphics/text_window/17.4bpp");
+static const u8 sTextWindowFrame18_Gfx[] = INCBIN_U8("graphics/text_window/18.4bpp");
+static const u8 sTextWindowFrame19_Gfx[] = INCBIN_U8("graphics/text_window/19.4bpp");
+static const u8 sTextWindowFrame20_Gfx[] = INCBIN_U8("graphics/text_window/20.4bpp");
const u16 gTextWindowFrame1_Pal[] = INCBIN_U16("graphics/text_window/1.gbapal");
static const u16 sTextWindowFrame2_Pal[] = INCBIN_U16("graphics/text_window/2.gbapal");