summaryrefslogtreecommitdiff
path: root/src/field/field_player_avatar.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/field/field_player_avatar.c')
-rw-r--r--src/field/field_player_avatar.c1757
1 files changed, 1757 insertions, 0 deletions
diff --git a/src/field/field_player_avatar.c b/src/field/field_player_avatar.c
new file mode 100644
index 000000000..e7947b704
--- /dev/null
+++ b/src/field/field_player_avatar.c
@@ -0,0 +1,1757 @@
+#include "global.h"
+#include "field_player_avatar.h"
+#include "bike.h"
+#include "event_data.h"
+#include "field_effect.h"
+#include "field_effect_helpers.h"
+#include "field_ground_effect.h"
+#include "field_map_obj.h"
+#include "field_map_obj_helpers.h"
+#include "fieldmap.h"
+#include "main.h"
+#include "map_object_constants.h"
+#include "menu.h"
+#include "metatile_behavior.h"
+#include "party_menu.h"
+#include "rng.h"
+#include "overworld.h"
+#include "rotating_gate.h"
+#include "script.h"
+#include "songs.h"
+#include "sound.h"
+#include "strings2.h"
+#include "task.h"
+#include "tv.h"
+#include "wild_encounter.h"
+
+EWRAM_DATA struct PlayerAvatar gPlayerAvatar = {0};
+
+//Functions
+static bool8 sub_8058854(struct MapObject *, u8);
+static void npc_clear_strange_bits(struct MapObject *a);
+static void MovePlayerAvatarUsingKeypadInput(u8 a, u16 b, u16 c);
+static void PlayerAllowForcedMovementIfMovingSameDirection(void);
+static u8 TryDoMetatileBehaviorForcedMovement(void);
+static u8 GetForcedMovementByMetatileBehavior(void);
+static void MovePlayerNotOnBike(u8 a, u16 b);
+static u8 CheckMovementInputNotOnBike(u8 a);
+static u8 CheckForPlayerAvatarCollision(u8 a);
+static u8 sub_8058EF0(s16 a, s16 b, u8 c);
+static bool8 ShouldJumpLedge(s16 a, s16 b, u8 c);
+static u8 sub_8058F6C(s16 a, s16 b, u8 c);
+static void check_acro_bike_metatile(int unused1, int unused2, u8 c, u8 *d);
+static void DoPlayerAvatarTransition(void);
+static bool8 player_is_anim_in_certain_ranges(void);
+static bool8 sub_80592A4(void);
+static bool8 PlayerIsAnimActive(void);
+static bool8 PlayerCheckIfAnimFinishedOrInactive(void);
+static void PlayerNotOnBikeCollide(u8 a);
+static void PlayCollisionSoundIfNotFacingWarp(u8 a);
+static void sub_8059D60(struct MapObject *a);
+static void StartStrengthAnim(u8 a, u8 b);
+static void sub_8059F94(void);
+static void sub_805A06C(void);
+
+static bool8 (*const gUnknown_0830FB58[])(u8) =
+{
+ MetatileBehavior_IsTrickHouseSlipperyFloor,
+ MetatileBehavior_IsIce_2,
+ MetatileBehavior_IsWalkSouth,
+ MetatileBehavior_IsWalkNorth,
+ MetatileBehavior_IsWalkWest,
+ MetatileBehavior_IsWalkEast,
+ MetatileBehavior_IsSouthwardCurrent,
+ MetatileBehavior_IsNorthwardCurrent,
+ MetatileBehavior_IsWestwardCurrent,
+ MetatileBehavior_IsEastwardCurrent,
+ MetatileBehavior_IsSlideSouth,
+ MetatileBehavior_IsSlideNorth,
+ MetatileBehavior_IsSlideWest,
+ MetatileBehavior_IsSlideEast,
+ MetatileBehavior_IsWaterfall,
+ MetatileBehavior_0xBB,
+ MetatileBehavior_0xBC,
+ MetatileBehavior_IsMuddySlope,
+};
+static u8 (*const gUnknown_0830FBA0[])(void) =
+{
+ ForcedMovement_None,
+ ForcedMovement_Slip,
+ ForcedMovement_Slip,
+ sub_8058AAC,
+ sub_8058AC4,
+ sub_8058ADC,
+ sub_8058AF4,
+ sub_8058B0C,
+ sub_8058B24,
+ sub_8058B3C,
+ sub_8058B54,
+ ForcedMovement_SlideSouth,
+ ForcedMovement_SlideNorth,
+ ForcedMovement_SlideWest,
+ ForcedMovement_SlideEast,
+ sub_8058B0C,
+ sub_8058C04,
+ sub_8058C10,
+ ForcedMovement_MuddySlope,
+};
+static void (*const gUnknown_0830FBEC[])(u8, u16) =
+{
+ PlayerNotOnBikeNotMoving,
+ PlayerNotOnBikeTurningInPlace,
+ sub_8058D0C,
+};
+static bool8 (*const gUnknown_0830FBF8[])(u8) =
+{
+ MetatileBehavior_IsBumpySlope,
+ MetatileBehavior_IsIsolatedVerticalRail,
+ MetatileBehavior_IsIsolatedHorizontalRail,
+ MetatileBehavior_IsVerticalRail,
+ MetatileBehavior_IsHorizontalRail,
+};
+static const u8 gUnknown_0830FC0C[] = {9, 10, 11, 12, 13};
+static void (*const gUnknown_0830FC14[])(struct MapObject *) =
+{
+ PlayerAvatarTransition_Normal,
+ PlayerAvatarTransition_MachBike,
+ PlayerAvatarTransition_AcroBike,
+ PlayerAvatarTransition_Surfing,
+ PlayerAvatarTransition_Underwater,
+ sub_80591F4,
+ nullsub_49,
+ nullsub_49,
+};
+static bool8 (*const gUnknown_0830FC34[])(u8) =
+{
+ MetatileBehavior_IsSouthArrowWarp,
+ MetatileBehavior_IsNorthArrowWarp,
+ MetatileBehavior_IsWestArrowWarp,
+ MetatileBehavior_IsEastArrowWarp,
+};
+static const u8 sRivalAvatarGfxIds[][2] =
+{
+ {MAP_OBJ_GFX_RIVAL_BRENDAN_NORMAL, MAP_OBJ_GFX_RIVAL_MAY_NORMAL},
+ {MAP_OBJ_GFX_RIVAL_BRENDAN_MACH_BIKE, MAP_OBJ_GFX_RIVAL_MAY_MACH_BIKE},
+ {MAP_OBJ_GFX_RIVAL_BRENDAN_ACRO_BIKE, MAP_OBJ_GFX_RIVAL_MAY_ACRO_BIKE},
+ {MAP_OBJ_GFX_RIVAL_BRENDAN_SURFING, MAP_OBJ_GFX_RIVAL_MAY_SURFING},
+ {MAP_OBJ_GFX_BRENDAN_UNDERWATER, MAP_OBJ_GFX_MAY_UNDERWATER},
+ {MAP_OBJ_GFX_RIVAL_BRENDAN_FIELD_MOVE, MAP_OBJ_GFX_RIVAL_MAY_FIELD_MOVE},
+ {MAP_OBJ_GFX_BRENDAN_FISHING, MAP_OBJ_GFX_MAY_FISHING},
+ {MAP_OBJ_GFX_BRENDAN_WATERING, MAP_OBJ_GFX_MAY_WATERING},
+};
+static const u8 sPlayerAvatarGfxIds[][2] =
+{
+ {MAP_OBJ_GFX_BRENDAN_NORMAL, MAP_OBJ_GFX_MAY_NORMAL},
+ {MAP_OBJ_GFX_BRENDAN_MACH_BIKE, MAP_OBJ_GFX_MAY_MACH_BIKE},
+ {MAP_OBJ_GFX_BRENDAN_ACRO_BIKE, MAP_OBJ_GFX_MAY_ACRO_BIKE},
+ {MAP_OBJ_GFX_BRENDAN_SURFING, MAP_OBJ_GFX_MAY_SURFING},
+ {MAP_OBJ_GFX_BRENDAN_UNDERWATER, MAP_OBJ_GFX_MAY_UNDERWATER},
+ {MAP_OBJ_GFX_BRENDAN_FIELD_MOVE, MAP_OBJ_GFX_MAY_FIELD_MOVE},
+ {MAP_OBJ_GFX_BRENDAN_FISHING, MAP_OBJ_GFX_MAY_FISHING},
+ {MAP_OBJ_GFX_BRENDAN_WATERING, MAP_OBJ_GFX_MAY_WATERING},
+};
+static const u8 gUnknown_0830FC64[2][5][2] =
+{
+ //male
+ {
+ {MAP_OBJ_GFX_BRENDAN_NORMAL, 1},
+ {MAP_OBJ_GFX_BRENDAN_MACH_BIKE, 2},
+ {MAP_OBJ_GFX_BRENDAN_ACRO_BIKE, 4},
+ {MAP_OBJ_GFX_BRENDAN_SURFING, 8},
+ {MAP_OBJ_GFX_BRENDAN_UNDERWATER, 16},
+ },
+ //female
+ {
+ {MAP_OBJ_GFX_MAY_NORMAL, 1},
+ {MAP_OBJ_GFX_MAY_MACH_BIKE, 2},
+ {MAP_OBJ_GFX_MAY_ACRO_BIKE, 4},
+ {MAP_OBJ_GFX_MAY_SURFING, 8},
+ {MAP_OBJ_GFX_MAY_UNDERWATER, 16},
+ }
+};
+static bool8 (*const gUnknown_0830FC78[])(u8) = //Duplicate of gUnknown_0830FC34
+{
+ MetatileBehavior_IsSouthArrowWarp,
+ MetatileBehavior_IsNorthArrowWarp,
+ MetatileBehavior_IsWestArrowWarp,
+ MetatileBehavior_IsEastArrowWarp,
+};
+static u8 (*const gUnknown_0830FC88[])(struct Task *, struct MapObject *, struct MapObject *) =
+{
+ sub_8059E84,
+ sub_8059EA4,
+ sub_8059F40,
+};
+static u8 (*const gUnknown_0830FC94[])(struct Task *, struct MapObject *) =
+{
+ sub_805A000,
+};
+static u8 (*const gUnknown_0830FC98[])(struct Task *, struct MapObject *) =
+{
+ sub_805A0D8,
+ sub_805A100,
+ sub_805A178,
+ sub_805A1B8,
+};
+
+fieldmap_object_null_cb(sub_80587B4, sub_80587D8);
+
+void player_step(u8 direction, u16 newKeys, u16 heldKeys)
+{
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ sub_8059D60(playerMapObj);
+ if (gPlayerAvatar.unk6 == 0)
+ {
+ sub_80E5B38(newKeys, heldKeys);
+ if (!sub_8058854(playerMapObj, direction))
+ {
+ npc_clear_strange_bits(playerMapObj);
+ DoPlayerAvatarTransition();
+ if (TryDoMetatileBehaviorForcedMovement() == 0)
+ {
+ MovePlayerAvatarUsingKeypadInput(direction, newKeys, heldKeys);
+ PlayerAllowForcedMovementIfMovingSameDirection();
+ }
+ }
+ }
+}
+
+static bool8 sub_8058854(struct MapObject *playerMapObj, u8 direction)
+{
+ if (FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(playerMapObj)
+ && !FieldObjectClearAnimIfSpecialAnimFinished(playerMapObj))
+ {
+ u8 specialAnim = FieldObjectGetSpecialAnim(playerMapObj);
+
+ if (specialAnim > 24 && specialAnim < 29 && direction != DIR_NONE && playerMapObj->placeholder18 != direction)
+ {
+ FieldObjectClearAnim(playerMapObj);
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void npc_clear_strange_bits(struct MapObject *a)
+{
+ a->mapobj_bit_12 = 0;
+ a->mapobj_bit_10 = 0;
+ a->mapobj_bit_9 = 0;
+ gPlayerAvatar.flags &= ~PLAYER_AVATAR_FLAG_DASH;
+}
+
+static void MovePlayerAvatarUsingKeypadInput(u8 direction, u16 newKeys, u16 heldKeys)
+{
+ if ((gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_MACH_BIKE)
+ || (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_ACRO_BIKE))
+ MovePlayerOnBike(direction, newKeys, heldKeys);
+ else
+ MovePlayerNotOnBike(direction, heldKeys);
+}
+
+static void PlayerAllowForcedMovementIfMovingSameDirection(void)
+{
+ if (gPlayerAvatar.running2 == 2)
+ gPlayerAvatar.flags &= ~PLAYER_AVATAR_FLAG_5;
+}
+
+static u8 TryDoMetatileBehaviorForcedMovement(void)
+{
+ return gUnknown_0830FBA0[GetForcedMovementByMetatileBehavior()]();
+}
+
+static u8 GetForcedMovementByMetatileBehavior(void)
+{
+ u8 i;
+
+ if (!(gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_5))
+ {
+ u8 r5 = gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_1E;
+
+ for (i = 0; i < 18; i++)
+ {
+ if (gUnknown_0830FB58[i](r5))
+ return i + 1;
+ }
+ }
+ return 0;
+}
+
+u8 ForcedMovement_None(void)
+{
+ if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_6)
+ {
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ playerMapObj->mapobj_bit_9 = 0;
+ playerMapObj->mapobj_bit_11 = 1;
+ FieldObjectSetDirection(playerMapObj, playerMapObj->mapobj_unk_18);
+ gPlayerAvatar.flags &= ~PLAYER_AVATAR_FLAG_6;
+ }
+ return 0;
+}
+
+static u8 DoForcedMovement(u8 direction, void (*b)(u8))
+{
+ struct PlayerAvatar *playerAvatar = &gPlayerAvatar;
+ u8 collisionType = CheckForPlayerAvatarCollision(direction);
+
+ playerAvatar->flags |= PLAYER_AVATAR_FLAG_6;
+ if (collisionType != 0)
+ {
+ ForcedMovement_None();
+ if (collisionType <= 4)
+ {
+ return 0;
+ }
+ else
+ {
+ if (collisionType == COLLISION_LEDGE_JUMP)
+ PlayerJumpLedge(direction);
+ playerAvatar->flags |= PLAYER_AVATAR_FLAG_6;
+ playerAvatar->running2 = 2;
+ return 1;
+ }
+ }
+ else
+ {
+ playerAvatar->running2 = 2;
+ b(direction);
+ return 1;
+ }
+}
+
+static u8 DoForcedMovementInCurrentDirection(void (*a)(u8))
+{
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ playerMapObj->mapobj_bit_10 = 1;
+ return DoForcedMovement(playerMapObj->placeholder18, a);
+}
+
+u8 ForcedMovement_Slip(void)
+{
+ return DoForcedMovementInCurrentDirection(sub_80593C4);
+}
+
+u8 sub_8058AAC(void)
+{
+ return DoForcedMovement(1, PlayerGoSpeed0);
+}
+
+u8 sub_8058AC4(void)
+{
+ return DoForcedMovement(2, PlayerGoSpeed0);
+}
+
+u8 sub_8058ADC(void)
+{
+ return DoForcedMovement(3, PlayerGoSpeed0);
+}
+
+u8 sub_8058AF4(void)
+{
+ return DoForcedMovement(4, PlayerGoSpeed0);
+}
+
+u8 sub_8058B0C(void)
+{
+ return DoForcedMovement(1, npc_use_some_d2s);
+}
+
+u8 sub_8058B24(void)
+{
+ return DoForcedMovement(2, npc_use_some_d2s);
+}
+
+u8 sub_8058B3C(void)
+{
+ return DoForcedMovement(3, npc_use_some_d2s);
+}
+
+u8 sub_8058B54(void)
+{
+ return DoForcedMovement(4, npc_use_some_d2s);
+}
+
+static u8 ForcedMovement_Slide(u8 direction, void (*b)(u8))
+{
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ playerMapObj->mapobj_bit_10 = 1;
+ playerMapObj->mapobj_bit_9 = 1;
+ return DoForcedMovement(direction, b);
+}
+
+u8 ForcedMovement_SlideSouth(void)
+{
+ return ForcedMovement_Slide(1, sub_80593C4);
+}
+
+u8 ForcedMovement_SlideNorth(void)
+{
+ return ForcedMovement_Slide(2, sub_80593C4);
+}
+
+u8 ForcedMovement_SlideWest(void)
+{
+ return ForcedMovement_Slide(3, sub_80593C4);
+}
+
+u8 ForcedMovement_SlideEast(void)
+{
+ return ForcedMovement_Slide(4, sub_80593C4);
+}
+
+u8 sub_8058C04(void)
+{
+ sub_8059F94();
+ return 1;
+}
+
+u8 sub_8058C10(void)
+{
+ sub_805A06C();
+ return 1;
+}
+
+u8 ForcedMovement_MuddySlope(void)
+{
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ if (playerMapObj->placeholder18 != 2 || GetPlayerSpeed() <= 3)
+ {
+ sub_80E6010(0);
+ playerMapObj->mapobj_bit_9 = 1;
+ return DoForcedMovement(1, sub_80593C4);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static void MovePlayerNotOnBike(u8 direction, u16 heldKeys)
+{
+ gUnknown_0830FBEC[CheckMovementInputNotOnBike(direction)](direction, heldKeys);
+}
+
+static u8 CheckMovementInputNotOnBike(u8 direction)
+{
+ if (direction == DIR_NONE)
+ {
+ gPlayerAvatar.running2 = 0;
+ return 0;
+ }
+ else if (direction != player_get_direction_upper_nybble() && gPlayerAvatar.running2 != 2)
+ {
+ gPlayerAvatar.running2 = 1;
+ return 1;
+ }
+ else
+ {
+ gPlayerAvatar.running2 = 2;
+ return 2;
+ }
+}
+
+void PlayerNotOnBikeNotMoving(u8 direction, u16 heldKeys)
+{
+ PlayerFaceDirection(player_get_direction_lower_nybble());
+}
+
+void PlayerNotOnBikeTurningInPlace(u8 direction, u16 heldKeys)
+{
+ PlayerTurnInPlace(direction);
+}
+
+void sub_8058D0C(u8 direction, u16 heldKeys)
+{
+ u8 r1 = CheckForPlayerAvatarCollision(direction);
+
+ switch (r1)
+ {
+ case 6:
+ PlayerJumpLedge(direction);
+ return;
+ default:
+ if (r1 > 8 || r1 < 5)
+ PlayerNotOnBikeCollide(direction);
+ return;
+ case 0:
+ if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING)
+ {
+ sub_80593C4(direction);
+ return;
+ }
+ if (!(gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_4) && (heldKeys & B_BUTTON) && FlagGet(SYS_B_DASH)
+ && IsRunningDisallowed(gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_1E) == 0)
+ {
+ sub_805940C(direction);
+ gPlayerAvatar.flags |= PLAYER_AVATAR_FLAG_DASH;
+ }
+ else
+ {
+ PlayerGoSpeed0(direction);
+ }
+ }
+}
+
+static u8 CheckForPlayerAvatarCollision(u8 direction)
+{
+ s16 x, y;
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ x = playerMapObj->coords2.x;
+ y = playerMapObj->coords2.y;
+ MoveCoords(direction, &x, &y);
+ return CheckForFieldObjectCollision(playerMapObj, x, y, direction, MapGridGetMetatileBehaviorAt(x, y));
+}
+
+u8 CheckForFieldObjectCollision(struct MapObject *a, s16 x, s16 y, u8 direction, u8 e)
+{
+ u8 collision;
+
+ collision = npc_block_way(a, x, y, direction);
+ if (collision == 3 && sub_8058EF0(x, y, direction))
+ return 5;
+ if (ShouldJumpLedge(x, y, direction))
+ {
+ IncrementGameStat(0x2B);
+ return COLLISION_LEDGE_JUMP;
+ }
+ if (collision == 4 && sub_8058F6C(x, y, direction))
+ return 7;
+
+ if (collision == 0)
+ {
+ if (CheckForRotatingGatePuzzleCollision(direction, x, y))
+ return 8;
+ check_acro_bike_metatile(x, y, e, &collision);
+ }
+ return collision;
+}
+
+static u8 sub_8058EF0(s16 a, s16 b, u8 c)
+{
+ if ((gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING)
+ && MapGridGetZCoordAt(a, b) == 3
+ && GetFieldObjectIdByXYZ(a, b, 3) == 16)
+ {
+ sub_805A20C(c);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static bool8 ShouldJumpLedge(s16 a, s16 b, u8 c)
+{
+ if (GetLedgeJumpDirection(a, b, c) != 0)
+ return 1;
+ else
+ return 0;
+}
+
+static u8 sub_8058F6C(s16 a, s16 b, u8 c)
+{
+ if (FlagGet(SYS_USE_STRENGTH))
+ {
+ u8 mapObjectId = GetFieldObjectIdByXY(a, b);
+
+ if (mapObjectId != 16)
+ {
+ if (gMapObjects[mapObjectId].graphicsId == 0x57)
+ {
+ a = gMapObjects[mapObjectId].coords2.x;
+ b = gMapObjects[mapObjectId].coords2.y;
+ MoveCoords(c, &a, &b);
+ if (npc_block_way(&gMapObjects[mapObjectId], a, b, c) == 0
+ && MetatileBehavior_IsNonAnimDoor(MapGridGetMetatileBehaviorAt(a, b)) == 0)
+ {
+ StartStrengthAnim(mapObjectId, c);
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static void check_acro_bike_metatile(int unused1, int unused2, u8 c, u8 *d)
+{
+ u8 i;
+
+ for (i = 0; i < 5; i++)
+ {
+ if (gUnknown_0830FBF8[i](c))
+ {
+ *d = gUnknown_0830FC0C[i];
+ return;
+ }
+ }
+}
+
+void SetPlayerAvatarTransitionFlags(u16 a)
+{
+ gPlayerAvatar.bike |= a;
+ DoPlayerAvatarTransition();
+}
+
+static void DoPlayerAvatarTransition(void)
+{
+ u8 i;
+ u32 flags = gPlayerAvatar.bike;
+
+ if (flags != 0)
+ {
+ for (i = 0; i < 8; i++, flags >>= 1)
+ {
+#ifdef NONMATCHING
+ if (flags & 1)
+ {
+ gUnknown_0830FC14[i](&gMapObjects[gPlayerAvatar.mapObjectId]);
+ }
+#else
+ if (flags & 1)
+ {
+ register void (*const *funcs)(struct MapObject *) asm("r0") = gUnknown_0830FC14;
+ funcs[i](&gMapObjects[gPlayerAvatar.mapObjectId]);
+ }
+#endif
+ }
+ gPlayerAvatar.bike = 0;
+ }
+}
+
+void nullsub_49(struct MapObject *a)
+{
+}
+
+void PlayerAvatarTransition_Normal(struct MapObject *a)
+{
+ sub_805B980(a, GetPlayerAvatarGraphicsIdByStateId(0));
+ FieldObjectTurn(a, a->placeholder18);
+ SetPlayerAvatarStateMask(1);
+}
+
+void PlayerAvatarTransition_MachBike(struct MapObject *a)
+{
+ sub_805B980(a, GetPlayerAvatarGraphicsIdByStateId(1));
+ FieldObjectTurn(a, a->placeholder18);
+ SetPlayerAvatarStateMask(2);
+ BikeClearState(0, 0);
+}
+
+void PlayerAvatarTransition_AcroBike(struct MapObject *a)
+{
+ sub_805B980(a, GetPlayerAvatarGraphicsIdByStateId(2));
+ FieldObjectTurn(a, a->placeholder18);
+ SetPlayerAvatarStateMask(4);
+ BikeClearState(0, 0);
+ sub_80E6084();
+}
+
+void PlayerAvatarTransition_Surfing(struct MapObject *a)
+{
+ u8 unk;
+
+ sub_805B980(a, GetPlayerAvatarGraphicsIdByStateId(3));
+ FieldObjectTurn(a, a->placeholder18);
+ SetPlayerAvatarStateMask(8);
+ gFieldEffectArguments[0] = a->coords2.x;
+ gFieldEffectArguments[1] = a->coords2.y;
+ gFieldEffectArguments[2] = gPlayerAvatar.mapObjectId;
+ unk = FieldEffectStart(FLDEFF_SURF_BLOB);
+ a->mapobj_unk_1A = unk;
+ sub_8127ED0(unk, 1);
+}
+
+void PlayerAvatarTransition_Underwater(struct MapObject *a)
+{
+ sub_805B980(a, GetPlayerAvatarGraphicsIdByStateId(4));
+ FieldObjectTurn(a, a->placeholder18);
+ SetPlayerAvatarStateMask(16);
+ a->mapobj_unk_1A = sub_8128124(a->spriteId);
+}
+
+void sub_80591F4(struct MapObject *a)
+{
+ gPlayerAvatar.flags |= PLAYER_AVATAR_FLAG_5;
+}
+
+void sub_8059204(void)
+{
+ gPlayerAvatar.running1 = 0;
+ if (PlayerIsAnimActive())
+ {
+ if (!PlayerCheckIfAnimFinishedOrInactive())
+ {
+ if (!player_is_anim_in_certain_ranges())
+ gPlayerAvatar.running1 = 1;
+ }
+ else
+ {
+ if (!sub_80592A4())
+ gPlayerAvatar.running1 = 2;
+ }
+ }
+}
+
+static bool8 player_is_anim_in_certain_ranges(void)
+{
+ u8 unk = gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_1C;
+
+ if (unk < 4
+ || (unk >= 16 && unk < 0x15)
+ || (unk >= 25 && unk < 41)
+ || (unk >= 98 && unk < 110)
+ || (unk >= 122 && unk < 126))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static bool8 sub_80592A4(void)
+{
+ if (player_is_anim_in_certain_ranges() && gPlayerAvatar.running2 != 1)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static bool8 PlayerIsAnimActive(void)
+{
+ return FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(&gMapObjects[gPlayerAvatar.mapObjectId]);
+}
+
+static bool8 PlayerCheckIfAnimFinishedOrInactive(void)
+{
+ return FieldObjectCheckIfSpecialAnimFinishedOrInactive(&gMapObjects[gPlayerAvatar.mapObjectId]);
+}
+
+static void player_set_x22(u8 a)
+{
+ gMapObjects[gPlayerAvatar.mapObjectId].animId = a;
+}
+
+u8 player_get_x22(void)
+{
+ return gMapObjects[gPlayerAvatar.mapObjectId].animId;
+}
+
+static void sub_8059348(u8 a)
+{
+ FieldObjectForceSetSpecialAnim(&gMapObjects[gPlayerAvatar.mapObjectId], a);
+}
+
+void PlayerSetAnimId(u8 animId, u8 b)
+{
+ if (!PlayerIsAnimActive())
+ {
+ player_set_x22(b);
+ FieldObjectSetSpecialAnim(&gMapObjects[gPlayerAvatar.mapObjectId], animId);
+ }
+}
+
+void PlayerGoSpeed0(u8 a)
+{
+ PlayerSetAnimId(GetGoSpeed0AnimId(a), 2);
+}
+
+void sub_80593C4(u8 a)
+{
+ PlayerSetAnimId(sub_8060744(a), 2);
+}
+
+void npc_use_some_d2s(u8 a)
+{
+ PlayerSetAnimId(d2s_08064034(a), 2);
+}
+
+void sub_80593F4(u8 a)
+{
+ PlayerSetAnimId(sub_806079C(a), 2);
+}
+
+void sub_805940C(u8 a)
+{
+ PlayerSetAnimId(sub_80607F4(a), 2);
+}
+
+void PlayerOnBikeCollide(u8 a)
+{
+ PlayCollisionSoundIfNotFacingWarp(a);
+ PlayerSetAnimId(GetStepInPlaceDelay16AnimId(a), 2);
+}
+
+static void PlayerNotOnBikeCollide(u8 a)
+{
+ PlayCollisionSoundIfNotFacingWarp(a);
+ PlayerSetAnimId(GetStepInPlaceDelay32AnimId(a), 2);
+}
+
+void PlayerFaceDirection(u8 direction)
+{
+ PlayerSetAnimId(GetFaceDirectionAnimId(direction), 1);
+}
+
+void PlayerTurnInPlace(u8 direction)
+{
+ PlayerSetAnimId(GetStepInPlaceDelay8AnimId(direction), 1);
+}
+
+void PlayerJumpLedge(u8 direction)
+{
+ PlaySE(SE_DANSA);
+ PlayerSetAnimId(GetJumpLedgeAnimId(direction), 8);
+}
+
+void sub_80594C0(void)
+{
+ if (gPlayerAvatar.running1 == 2 || gPlayerAvatar.running1 == 0)
+ {
+ if (player_should_look_direction_be_enforced_upon_movement())
+ sub_8059348(GetFaceDirectionAnimId(gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_18));
+ }
+}
+
+void sub_8059504(u8 a)
+{
+ PlayerSetAnimId(sub_80609D8(a), 1);
+}
+
+//normal to wheelie
+void PlayerStartWheelie(u8 a)
+{
+ PlayerSetAnimId(sub_8060A04(a), 1);
+}
+
+void sub_8059534(u8 a)
+{
+ PlayerSetAnimId(sub_8060A30(a), 1);
+}
+
+void sub_805954C(u8 a)
+{
+ PlaySE(SE_JITE_PYOKO);
+ PlayerSetAnimId(sub_8060A5C(a), 1);
+}
+
+void sub_8059570(u8 a)
+{
+ PlaySE(SE_JITE_PYOKO);
+ PlayerSetAnimId(sub_8060A88(a), 2);
+}
+
+void sub_8059594(u8 a)
+{
+ PlaySE(SE_JITE_PYOKO);
+ PlayerSetAnimId(sub_8060AB4(a), 8);
+}
+
+void sub_80595B8(u8 direction)
+{
+ PlaySE(SE_JITE_PYOKO);
+ PlayerSetAnimId(sub_8060878(direction), 1);
+}
+
+void sub_80595DC(u8 direction)
+{
+ PlaySE(SE_WALL_HIT);
+ PlayerSetAnimId(sub_8060AE0(direction), 2);
+}
+
+void sub_8059600(u8 a)
+{
+ PlayerSetAnimId(sub_8060B0C(a), 2);
+}
+
+void sub_8059618(u8 a)
+{
+ PlayerSetAnimId(sub_8060B38(a), 2);
+}
+
+void sub_8059630(u8 a)
+{
+ PlayerSetAnimId(sub_8060B64(a), 2);
+}
+
+static void PlayCollisionSoundIfNotFacingWarp(u8 a)
+{
+ s16 x, y;
+ u8 unk = gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_1E;
+
+ if (!gUnknown_0830FC34[a - 1](unk))
+ {
+ if (a == 2)
+ {
+ PlayerGetDestCoords(&x, &y);
+ MoveCoords(2, &x, &y);
+ if (MetatileBehavior_IsWarpDoor(MapGridGetMetatileBehaviorAt(x, y)))
+ return;
+ }
+ PlaySE(SE_WALL_HIT);
+ }
+}
+
+void GetXYCoordsOneStepInFrontOfPlayer(s16 *x, s16 *y)
+{
+ *x = gMapObjects[gPlayerAvatar.mapObjectId].coords2.x;
+ *y = gMapObjects[gPlayerAvatar.mapObjectId].coords2.y;
+ MoveCoords(player_get_direction_lower_nybble(), x, y);
+}
+
+void PlayerGetDestCoords(s16 *x, s16 *y)
+{
+ *x = gMapObjects[gPlayerAvatar.mapObjectId].coords2.x;
+ *y = gMapObjects[gPlayerAvatar.mapObjectId].coords2.y;
+}
+
+u8 player_get_direction_lower_nybble(void)
+{
+ return gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_18;
+}
+
+u8 player_get_direction_upper_nybble(void)
+{
+ return gMapObjects[gPlayerAvatar.mapObjectId].placeholder18;
+}
+
+u8 PlayerGetZCoord(void)
+{
+ return gMapObjects[gPlayerAvatar.mapObjectId].elevation;
+}
+
+void unref_sub_8059790(s16 a, s16 b)
+{
+ sub_805C058(&gMapObjects[gPlayerAvatar.mapObjectId], a, b);
+}
+
+u8 TestPlayerAvatarFlags(u8 a)
+{
+ return gPlayerAvatar.flags & a;
+}
+
+u8 sub_80597D0(void)
+{
+ return gPlayerAvatar.flags;
+}
+
+u8 GetPlayerAvatarObjectId(void)
+{
+ return gPlayerAvatar.spriteId;
+}
+
+void sub_80597E8(void)
+{
+ ForcedMovement_None();
+}
+
+void sub_80597F4(void)
+{
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ npc_clear_strange_bits(playerMapObj);
+ FieldObjectSetDirection(playerMapObj, playerMapObj->mapobj_unk_18);
+ if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE))
+ {
+ sub_80E6084();
+ sub_80E6010(0);
+ }
+}
+
+u8 GetRivalAvatarGraphicsIdByStateIdAndGender(u8 state, u8 gender)
+{
+ return sRivalAvatarGfxIds[state][gender];
+}
+
+static u8 GetPlayerAvatarGraphicsIdByStateIdAndGender(u8 state, u8 gender)
+{
+ return sPlayerAvatarGfxIds[state][gender];
+}
+
+u8 GetPlayerAvatarGraphicsIdByStateId(u8 state)
+{
+ return GetPlayerAvatarGraphicsIdByStateIdAndGender(state, gPlayerAvatar.gender);
+}
+
+u8 unref_GetRivalAvatarGenderByGraphcsId(u8 gfxId)
+{
+ switch (gfxId)
+ {
+ case MAP_OBJ_GFX_RIVAL_MAY_NORMAL:
+ case MAP_OBJ_GFX_RIVAL_MAY_MACH_BIKE:
+ case MAP_OBJ_GFX_RIVAL_MAY_ACRO_BIKE:
+ case MAP_OBJ_GFX_RIVAL_MAY_SURFING:
+ case MAP_OBJ_GFX_RIVAL_MAY_FIELD_MOVE:
+ case MAP_OBJ_GFX_MAY_UNDERWATER:
+ case MAP_OBJ_GFX_MAY_FISHING:
+ case MAP_OBJ_GFX_MAY_WATERING:
+ return FEMALE;
+ default:
+ return MALE;
+ }
+}
+
+u8 GetPlayerAvatarGenderByGraphicsId(u8 gfxId)
+{
+ switch (gfxId)
+ {
+ case MAP_OBJ_GFX_MAY_NORMAL:
+ case MAP_OBJ_GFX_MAY_MACH_BIKE:
+ case MAP_OBJ_GFX_MAY_ACRO_BIKE:
+ case MAP_OBJ_GFX_MAY_SURFING:
+ case MAP_OBJ_GFX_MAY_FIELD_MOVE:
+ case MAP_OBJ_GFX_MAY_UNDERWATER:
+ case MAP_OBJ_GFX_MAY_FISHING:
+ case MAP_OBJ_GFX_MAY_WATERING:
+ return FEMALE;
+ default:
+ return MALE;
+ }
+}
+
+bool8 PartyHasMonWithSurf(void)
+{
+ u8 i;
+
+ if (!TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING))
+ {
+ for (i = 0; i < 6; i++)
+ {
+ if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) == 0)
+ break;
+ if (pokemon_has_move(&gPlayerParty[i], 0x39))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool8 IsPlayerSurfingNorth(void)
+{
+ if (player_get_direction_upper_nybble() == DIR_NORTH && TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+bool8 IsPlayerFacingSurfableFishableWater(void)
+{
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+ s16 x = playerMapObj->coords2.x;
+ s16 y = playerMapObj->coords2.y;
+
+ MoveCoords(playerMapObj->mapobj_unk_18, &x, &y);
+ if (npc_block_way(playerMapObj, x, y, playerMapObj->mapobj_unk_18) == 3 && PlayerGetZCoord() == 3
+ && MetatileBehavior_IsSurfableFishableWater(MapGridGetMetatileBehaviorAt(x, y)))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void ClearPlayerAvatarInfo(void)
+{
+ //TODO: 0x24 should be the size of gPlayerAvatar
+ memset(&gPlayerAvatar, 0, sizeof(struct PlayerAvatar));
+}
+
+void SetPlayerAvatarStateMask(u8 a)
+{
+ gPlayerAvatar.flags &= 0xE0;
+ gPlayerAvatar.flags |= a;
+}
+
+static u8 GetPlayerAvatarStateTransitionByGraphicsId(u8 a, u8 gender)
+{
+ u8 i;
+
+ for (i = 0; i < 5; i++)
+ {
+ if (gUnknown_0830FC64[gender][i][0] == a)
+ return gUnknown_0830FC64[gender][i][1];
+ }
+ return 1;
+}
+
+u8 GetPlayerAvatarGraphicsIdByCurrentState(void)
+{
+ u8 i;
+ u8 r5 = gPlayerAvatar.flags;
+
+ for (i = 0; i < 5; i++)
+ {
+ if (gUnknown_0830FC64[gPlayerAvatar.gender][i][1] & r5)
+ return gUnknown_0830FC64[gPlayerAvatar.gender][i][0];
+ }
+ return 0;
+}
+
+void SetPlayerAvatarExtraStateTransition(u8 a, u8 b)
+{
+ u8 unk = GetPlayerAvatarStateTransitionByGraphicsId(a, gPlayerAvatar.gender);
+
+ gPlayerAvatar.bike |= unk | b;
+ DoPlayerAvatarTransition();
+}
+
+void InitPlayerAvatar(s16 x, s16 y, u8 direction, u8 gender)
+{
+ struct MapObjectTemplate playerMapObjTemplate;
+ u8 mapObjectId;
+ struct MapObject *mapObject;
+
+ playerMapObjTemplate.localId = 0xFF;
+ playerMapObjTemplate.graphicsId = GetPlayerAvatarGraphicsIdByStateIdAndGender(0, gender);
+ playerMapObjTemplate.x = x - 7;
+ playerMapObjTemplate.y = y - 7;
+ playerMapObjTemplate.elevation = 0;
+ playerMapObjTemplate.movementType = 11;
+ playerMapObjTemplate.unkA_0 = 0;
+ playerMapObjTemplate.unkA_4 = 0;
+ playerMapObjTemplate.unkC = 0;
+ playerMapObjTemplate.unkE = 0;
+ playerMapObjTemplate.script = NULL;
+ playerMapObjTemplate.flagId = 0;
+ mapObjectId = SpawnSpecialFieldObject(&playerMapObjTemplate);
+ mapObject = &gMapObjects[mapObjectId];
+ mapObject->mapobj_bit_16 = 1;
+ mapObject->mapobj_unk_1B = sub_8126B54();
+ FieldObjectTurn(mapObject, direction);
+ ClearPlayerAvatarInfo();
+ gPlayerAvatar.running2 = 0;
+ gPlayerAvatar.running1 = 0;
+ gPlayerAvatar.mapObjectId = mapObjectId;
+ gPlayerAvatar.spriteId = mapObject->spriteId;
+ gPlayerAvatar.gender = gender;
+ SetPlayerAvatarStateMask(0x21);
+}
+
+void sub_8059B88(u8 a)
+{
+ gMapObjects[gPlayerAvatar.mapObjectId].mapobj_bit_13 = a;
+ if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING))
+ gSprites[gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_1A].invisible = a;
+}
+
+void sub_8059BF4(void)
+{
+ sub_805B980(&gMapObjects[gPlayerAvatar.mapObjectId], GetPlayerAvatarGraphicsIdByStateId(5));
+ StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], 0);
+}
+
+void sub_8059C3C(u8 a)
+{
+ sub_805B980(&gMapObjects[gPlayerAvatar.mapObjectId], GetPlayerAvatarGraphicsIdByStateId(6));
+ StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], sub_805FDE8(a));
+}
+
+void sub_8059C94(u8 a)
+{
+ sub_805B980(&gMapObjects[gPlayerAvatar.mapObjectId], GetPlayerAvatarGraphicsIdByStateId(2));
+ StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], sub_805FD98(a));
+ SeekSpriteAnim(&gSprites[gPlayerAvatar.spriteId], 1);
+}
+
+void sub_8059D08(u8 a)
+{
+ sub_805B980(&gMapObjects[gPlayerAvatar.mapObjectId], GetPlayerAvatarGraphicsIdByStateId(7));
+ StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], FieldObjectDirectionToImageAnimId(a));
+}
+
+static void sub_8059D60(struct MapObject *a)
+{
+ s16 x;
+ s16 y;
+ u8 r6;
+ u8 r8 = a->mapobj_unk_1E;
+
+ for (x = 0, r6 = 1; x < 4; x++, r6++)
+ {
+ if (gUnknown_0830FC78[x](r8) && r6 == a->placeholder18)
+ {
+ x = a->coords2.x;
+ y = a->coords2.y;
+ MoveCoords(r6, &x, &y);
+ sub_8126BC4(a->mapobj_unk_1B, r6, x, y);
+ return;
+ }
+ }
+ objid_set_invisible(a->mapobj_unk_1B);
+}
+
+/* Strength */
+
+static void sub_8059E2C(u8 taskId);
+
+static void StartStrengthAnim(u8 a, u8 b)
+{
+ u8 taskId = CreateTask(sub_8059E2C, 0xFF);
+
+ gTasks[taskId].data[1] = a;
+ gTasks[taskId].data[2] = b;
+ sub_8059E2C(taskId);
+}
+
+static void sub_8059E2C(u8 taskId)
+{
+ while (gUnknown_0830FC88[gTasks[taskId].data[0]](&gTasks[taskId],
+ &gMapObjects[gPlayerAvatar.mapObjectId],
+ &gMapObjects[gTasks[taskId].data[1]]))
+ ;
+}
+
+u8 sub_8059E84(struct Task *task, struct MapObject *b, struct MapObject *c)
+{
+ ScriptContext2_Enable();
+ gPlayerAvatar.unk6 = 1;
+ task->data[0]++;
+ return 0;
+}
+
+u8 sub_8059EA4(struct Task *task, struct MapObject *b, struct MapObject *c)
+{
+ if (!FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(b)
+ && !FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(c))
+ {
+ FieldObjectClearAnimIfSpecialAnimFinished(b);
+ FieldObjectClearAnimIfSpecialAnimFinished(c);
+ FieldObjectSetSpecialAnim(b, GetStepInPlaceDelay16AnimId((u8)task->data[2]));
+ FieldObjectSetSpecialAnim(c, GetSimpleGoAnimId((u8)task->data[2]));
+ gFieldEffectArguments[0] = c->coords2.x;
+ gFieldEffectArguments[1] = c->coords2.y;
+ gFieldEffectArguments[2] = c->elevation;
+ gFieldEffectArguments[3] = gSprites[c->spriteId].oam.priority;
+ FieldEffectStart(FLDEFF_DUST);
+ PlaySE(SE_W070);
+ task->data[0]++;
+ }
+ return 0;
+}
+
+u8 sub_8059F40(struct Task *task, struct MapObject *b, struct MapObject *c)
+{
+ if (FieldObjectCheckIfSpecialAnimFinishedOrInactive(b)
+ && FieldObjectCheckIfSpecialAnimFinishedOrInactive(c))
+ {
+ FieldObjectClearAnimIfSpecialAnimFinished(b);
+ FieldObjectClearAnimIfSpecialAnimFinished(c);
+ gPlayerAvatar.unk6 = 0;
+ ScriptContext2_Disable();
+ DestroyTask(FindTaskIdByFunc(sub_8059E2C));
+ }
+ return 0;
+}
+
+/* Some field effect */
+
+static void sub_8059FB4(u8 taskId);
+
+static void sub_8059F94(void)
+{
+ u8 taskId = CreateTask(sub_8059FB4, 0xFF);
+
+ sub_8059FB4(taskId);
+}
+
+static void sub_8059FB4(u8 taskId)
+{
+ while (gUnknown_0830FC94[gTasks[taskId].data[0]](&gTasks[taskId], &gMapObjects[gPlayerAvatar.mapObjectId]))
+ ;
+}
+
+u8 sub_805A000(struct Task *task, struct MapObject *mapObject)
+{
+ gPlayerAvatar.unk6 = 1;
+ if (FieldObjectClearAnimIfSpecialAnimFinished(mapObject))
+ {
+ PlaySE(SE_DANSA);
+ FieldObjectSetSpecialAnim(mapObject, sub_806084C(mapObject->mapobj_unk_18));
+ task->data[1]++;
+ if (task->data[1] > 1)
+ {
+ gPlayerAvatar.unk6 = 0;
+ gPlayerAvatar.bike |= 0x20;
+ DestroyTask(FindTaskIdByFunc(sub_8059FB4));
+ }
+ }
+ return 0;
+}
+
+/* Some field effect */
+
+static void sub_805A08C(u8 taskId);
+
+static void sub_805A06C(void)
+{
+ u8 taskId = CreateTask(sub_805A08C, 0xFF);
+
+ sub_805A08C(taskId);
+}
+
+static void sub_805A08C(u8 taskId)
+{
+ while (gUnknown_0830FC98[gTasks[taskId].data[0]](&gTasks[taskId], &gMapObjects[gPlayerAvatar.mapObjectId]))
+ ;
+}
+
+u8 sub_805A0D8(struct Task *task, struct MapObject *mapObject)
+{
+ task->data[0]++;
+ task->data[1] = mapObject->placeholder18;
+ gPlayerAvatar.unk6 = 1;
+ ScriptContext2_Enable();
+ PlaySE(SE_TK_WARPIN);
+ return 1;
+}
+
+u8 sub_805A100(struct Task *task, struct MapObject *mapObject)
+{
+ u8 directions[] = {DIR_WEST, DIR_EAST, DIR_NORTH, DIR_SOUTH};
+
+ if (FieldObjectClearAnimIfSpecialAnimFinished(mapObject))
+ {
+ u8 direction;
+
+ FieldObjectSetSpecialAnim(mapObject, GetFaceDirectionAnimId(direction = directions[mapObject->placeholder18 - 1]));
+ if (direction == (u8)task->data[1])
+ task->data[2]++;
+ task->data[0]++;
+ if (task->data[2] > 3 && direction == GetOppositeDirection(task->data[1]))
+ task->data[0]++;
+ }
+ return 0;
+}
+
+u8 sub_805A178(struct Task *task, struct MapObject *mapObject)
+{
+ const u8 arr[] = {16, 16, 17, 18, 19};
+
+ if (FieldObjectClearAnimIfSpecialAnimFinished(mapObject))
+ {
+ FieldObjectSetSpecialAnim(mapObject, arr[task->data[2]]);
+ task->data[0] = 1;
+ }
+ return 0;
+}
+
+u8 sub_805A1B8(struct Task *task, struct MapObject *mapObject)
+{
+ if (FieldObjectClearAnimIfSpecialAnimFinished(mapObject))
+ {
+ FieldObjectSetSpecialAnim(mapObject, GetSimpleGoAnimId(GetOppositeDirection(task->data[1])));
+ ScriptContext2_Disable();
+ gPlayerAvatar.unk6 = 0;
+ DestroyTask(FindTaskIdByFunc(sub_805A08C));
+ }
+ return 0;
+}
+
+/* Some Field effect */
+
+static void taskFF_0805D1D4(u8 taskId);
+static void sub_805A2D0(u8 taskId);
+
+void sub_805A20C(u8 a)
+{
+ u8 taskId;
+
+ ScriptContext2_Enable();
+ sav1_reset_battle_music_maybe();
+ sub_8053F84();
+ gPlayerAvatar.flags &= ~PLAYER_AVATAR_FLAG_SURFING;
+ gPlayerAvatar.flags |= PLAYER_AVATAR_FLAG_ON_FOOT;
+ gPlayerAvatar.unk6 = 1;
+ taskId = CreateTask(taskFF_0805D1D4, 0xFF);
+ gTasks[taskId].data[0] = a;
+ taskFF_0805D1D4(taskId);
+}
+
+static void taskFF_0805D1D4(u8 taskId)
+{
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ if (FieldObjectIsSpecialAnimOrDirectionSequenceAnimActive(playerMapObj))
+ {
+ if (!FieldObjectClearAnimIfSpecialAnimFinished(playerMapObj))
+ return;
+ }
+ sub_8127ED0(playerMapObj->mapobj_unk_1A, 2);
+ FieldObjectSetSpecialAnim(playerMapObj, sub_80608D0((u8)gTasks[taskId].data[0]));
+ gTasks[taskId].func = sub_805A2D0;
+}
+
+static void sub_805A2D0(u8 taskId)
+{
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ if (FieldObjectClearAnimIfSpecialAnimFinished(playerMapObj))
+ {
+ sub_805B980(playerMapObj, GetPlayerAvatarGraphicsIdByStateId(0));
+ FieldObjectSetSpecialAnim(playerMapObj, GetFaceDirectionAnimId(playerMapObj->mapobj_unk_18));
+ gPlayerAvatar.unk6 = 0;
+ ScriptContext2_Disable();
+ DestroySprite(&gSprites[playerMapObj->mapobj_unk_1A]);
+ DestroyTask(taskId);
+ }
+}
+
+/* Fishing */
+
+static u8 (*const sFishingStateFuncs[])(struct Task *) =
+{
+ Fishing1,
+ Fishing2,
+ Fishing3,
+ Fishing4,
+ Fishing5,
+ Fishing6,
+ Fishing7,
+ Fishing8,
+ Fishing9,
+ Fishing10,
+ Fishing11,
+ Fishing12,
+ Fishing13,
+ Fishing14,
+ Fishing15,
+ Fishing16,
+};
+
+static void Task_Fishing(u8 taskId);
+static void sub_805A954(void);
+
+#define tStep data[0]
+#define tFrameCounter data[1]
+#define tNumDots data[2]
+#define tDotsRequired data[3]
+#define tRoundsPlayed data[12]
+#define tMinRoundsRequired data[13]
+#define tPlayerGfxId data[14]
+#define tFishingRod data[15]
+
+#define FISHING_START_ROUND 3
+#define FISHING_GOT_BITE 6
+#define FISHING_ON_HOOK 9
+#define FISHING_NO_BITE 11
+#define FISHING_GOT_AWAY 12
+#define FISHING_SHOW_RESULT 13
+
+void StartFishing(u8 rod)
+{
+ u8 taskId = CreateTask(Task_Fishing, 0xFF);
+
+ gTasks[taskId].tFishingRod = rod;
+ Task_Fishing(taskId);
+}
+
+static void Task_Fishing(u8 taskId)
+{
+ while (sFishingStateFuncs[gTasks[taskId].tStep](&gTasks[taskId]))
+ ;
+}
+
+u8 Fishing1(struct Task *task)
+{
+ ScriptContext2_Enable();
+ gPlayerAvatar.unk6 = 1;
+ task->tStep++;
+ return 0;
+}
+
+u8 Fishing2(struct Task *task)
+{
+ struct MapObject *playerMapObj;
+ const s16 arr1[] = {1, 1, 1};
+ const s16 arr2[] = {1, 3, 6};
+
+ task->tRoundsPlayed = 0;
+ task->tMinRoundsRequired = arr1[task->tFishingRod] + (Random() % arr2[task->tFishingRod]);
+ task->tPlayerGfxId = gMapObjects[gPlayerAvatar.mapObjectId].graphicsId;
+ playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+ FieldObjectClearAnimIfSpecialAnimActive(playerMapObj);
+ playerMapObj->mapobj_bit_11 = 1;
+ sub_8059C3C(playerMapObj->mapobj_unk_18);
+ task->tStep++;
+ return 0;
+}
+
+u8 Fishing3(struct Task *task)
+{
+ sub_805A954();
+
+ // Wait one second before starting dot game
+ task->tFrameCounter++;
+ if (task->tFrameCounter >= 60)
+ task->tStep++;
+ return 0;
+}
+
+u8 Fishing4(struct Task *task)
+{
+ u32 randVal;
+
+ MenuDisplayMessageBox();
+ task->tStep++;
+ task->tFrameCounter = 0;
+ task->tNumDots = 0;
+ randVal = Random();
+ randVal %= 10;
+ task->tDotsRequired = randVal + 1;
+ if (task->tRoundsPlayed == 0)
+ task->tDotsRequired = randVal + 4;
+ if (task->tDotsRequired >= 10)
+ task->tDotsRequired = 10;
+ return 1;
+}
+
+// Play a round of the dot game
+u8 Fishing5(struct Task *task)
+{
+ const u8 dot[] = _("·");
+
+ sub_805A954();
+ task->tFrameCounter++;
+ if (gMain.newKeys & A_BUTTON)
+ {
+ task->tStep = FISHING_NO_BITE;
+ if (task->tRoundsPlayed != 0)
+ task->tStep = FISHING_GOT_AWAY;
+ return 1;
+ }
+ else
+ {
+ if (task->tFrameCounter >= 20)
+ {
+ task->tFrameCounter = 0;
+ if (task->tNumDots >= task->tDotsRequired)
+ {
+ task->tStep++;
+ if (task->tRoundsPlayed != 0)
+ task->tStep++;
+ task->tRoundsPlayed++;
+ }
+ else
+ {
+ MenuPrint(dot, task->tNumDots + 4, 15);
+ task->tNumDots++;
+ }
+ }
+ return 0;
+ }
+}
+
+// Determine if fish bites
+u8 Fishing6(struct Task *task)
+{
+ sub_805A954();
+ task->tStep++;
+ if (!DoesCurrentMapHaveFishingMons() || (Random() & 1))
+ task->tStep = FISHING_NO_BITE;
+ else
+ StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], sub_805FE08(player_get_direction_lower_nybble()));
+ return 1;
+}
+
+// Oh! A Bite!
+u8 Fishing7(struct Task *task)
+{
+ sub_805A954();
+ MenuPrint(gOtherText_OhABite, 4, 17);
+ task->tStep++;
+ task->tFrameCounter = 0;
+ return 0;
+}
+
+// We have a bite. Now, wait for the player to press A, or the timer to expire.
+u8 Fishing8(struct Task *task)
+{
+ const s16 reelTimeouts[3] = {36, 33, 30};
+
+ sub_805A954();
+ task->tFrameCounter++;
+ if (task->tFrameCounter >= reelTimeouts[task->tFishingRod])
+ task->tStep = FISHING_GOT_AWAY;
+ else if (gMain.newKeys & A_BUTTON)
+ task->tStep++;
+ return 0;
+}
+
+// Determine if we're going to play the dot game again
+u8 Fishing9(struct Task *task)
+{
+ const s16 arr[][2] =
+ {
+ {0, 0},
+ {40, 10},
+ {70, 30}
+ };
+
+ sub_805A954();
+ task->tStep++;
+ if (task->tRoundsPlayed < task->tMinRoundsRequired)
+ {
+ task->tStep = FISHING_START_ROUND;
+ }
+ else if (task->tRoundsPlayed < 2)
+ {
+ // probability of having to play another round
+ s16 probability = Random() % 100;
+
+ if (arr[task->tFishingRod][task->tRoundsPlayed] > probability)
+ task->tStep = FISHING_START_ROUND;
+ }
+ return 0;
+}
+
+u8 Fishing10(struct Task *task)
+{
+ sub_805A954();
+ MenuPrintMessageDefaultCoords(gOtherText_PokeOnHook);
+ MenuDisplayMessageBox();
+ task->tStep++;
+ task->tFrameCounter = 0;
+ return 0;
+}
+
+u8 Fishing11(struct Task *task)
+{
+ if (task->tFrameCounter == 0)
+ sub_805A954();
+
+ if (task->tFrameCounter == 0)
+ {
+ if (MenuUpdateWindowText())
+ {
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ sub_805B980(playerMapObj, task->tPlayerGfxId);
+ FieldObjectTurn(playerMapObj, playerMapObj->placeholder18);
+ if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING)
+ sub_8127F28(gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_1A, 0, 0);
+ gSprites[gPlayerAvatar.spriteId].pos2.x = 0;
+ gSprites[gPlayerAvatar.spriteId].pos2.y = 0;
+ MenuZeroFillScreen();
+ task->tFrameCounter++;
+ return 0;
+ }
+ }
+
+ if (task->tFrameCounter != 0)
+ {
+ gPlayerAvatar.unk6 = 0;
+ ScriptContext2_Disable();
+ FishingWildEncounter(task->tFishingRod);
+ sub_80BE97C(1);
+ DestroyTask(FindTaskIdByFunc(Task_Fishing));
+ }
+ return 0;
+}
+
+// Not even a nibble
+u8 Fishing12(struct Task *task)
+{
+ sub_805A954();
+ StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], sub_805FDF8(player_get_direction_lower_nybble()));
+ MenuPrintMessageDefaultCoords(gOtherText_NotEvenANibble);
+ task->tStep = FISHING_SHOW_RESULT;
+ return 1;
+}
+
+// It got away
+u8 Fishing13(struct Task *task)
+{
+ sub_805A954();
+ StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], sub_805FDF8(player_get_direction_lower_nybble()));
+ MenuPrintMessageDefaultCoords(gOtherText_ItGotAway);
+ task->tStep++;
+ return 1;
+}
+
+// Display the message
+u8 Fishing14(struct Task *task)
+{
+ sub_805A954();
+ MenuDisplayMessageBox();
+ task->tStep++;
+ return 0;
+}
+
+u8 Fishing15(struct Task *task)
+{
+ sub_805A954();
+ if (gSprites[gPlayerAvatar.spriteId].animEnded)
+ {
+ struct MapObject *playerMapObj = &gMapObjects[gPlayerAvatar.mapObjectId];
+
+ sub_805B980(playerMapObj, task->tPlayerGfxId);
+ FieldObjectTurn(playerMapObj, playerMapObj->placeholder18);
+ if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING)
+ sub_8127F28(gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_1A, 0, 0);
+ gSprites[gPlayerAvatar.spriteId].pos2.x = 0;
+ gSprites[gPlayerAvatar.spriteId].pos2.y = 0;
+ task->tStep++;
+ }
+ return 0;
+}
+
+u8 Fishing16(struct Task *task)
+{
+ if (MenuUpdateWindowText())
+ {
+ gPlayerAvatar.unk6 = 0;
+ ScriptContext2_Disable();
+ UnfreezeMapObjects();
+ MenuZeroFillScreen();
+ sub_80BE97C(0);
+ DestroyTask(FindTaskIdByFunc(Task_Fishing));
+ }
+ return 0;
+}
+
+#undef tStep
+#undef tFrameCounter
+#undef tFishingRod
+
+static void sub_805A954(void)
+{
+ struct Sprite *playerSprite = &gSprites[gPlayerAvatar.spriteId];
+ u8 animCmdIndex;
+ u8 animType;
+
+ AnimateSprite(playerSprite);
+ playerSprite->pos2.x = 0;
+ playerSprite->pos2.y = 0;
+ animCmdIndex = playerSprite->animCmdIndex;
+ if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1)
+ {
+ animCmdIndex--;
+ }
+ else
+ {
+ playerSprite->animDelayCounter++;
+ if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1)
+ animCmdIndex--;
+ }
+ animType = playerSprite->anims[playerSprite->animNum][animCmdIndex].type;
+ if (animType == 1 || animType == 2 || animType == 3)
+ {
+ playerSprite->pos2.x = 8;
+ if (player_get_direction_lower_nybble() == 3)
+ playerSprite->pos2.x = -8;
+ }
+ if (animType == 5)
+ playerSprite->pos2.y = -8;
+ if (animType == 10 || animType == 11)
+ playerSprite->pos2.y = 8;
+ if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING)
+ sub_8127F28(gMapObjects[gPlayerAvatar.mapObjectId].mapobj_unk_1A, 1, playerSprite->pos2.y);
+}