pokeemerald/src/faraway_island.c
aaaaaa123456789 7dc95a0103 Undo PokeCodec's PRs
This commit undoes most of PokeCodec's PRs after the debate in chat. Some
harmless or completely superseded PRs have been left alone, as there is not
much benefit in attempting to undo them.

Reverts #1104, #1108, #1115, #1118, #1119, #1124, #1126, #1127, #1132, #1136,
#1137, #1139, #1140, #1144, #1148, #1149, #1150, #1153, #1155, #1177, #1179,
#1180, #1181, #1182 and #1183.
2020-09-13 06:30:55 -03:00

467 lines
16 KiB
C
Executable File

#include "global.h"
#include "event_data.h"
#include "event_object_movement.h"
#include "field_weather.h"
#include "fieldmap.h"
#include "metatile_behavior.h"
#include "sprite.h"
#include "constants/event_objects.h"
#include "constants/field_effects.h"
#include "constants/maps.h"
#include "constants/metatile_behaviors.h"
static u8 GetValidMewMoveDirection(u8);
static bool8 ShouldMewMoveNorth(struct ObjectEvent*, u8);
static bool8 ShouldMewMoveSouth(struct ObjectEvent*, u8);
static bool8 ShouldMewMoveEast(struct ObjectEvent*, u8);
static bool8 ShouldMewMoveWest(struct ObjectEvent*, u8);
static u8 GetRandomMewDirectionCandidate(u8);
static bool8 CanMewMoveToCoords(s16, s16);
static EWRAM_DATA u8 sGrassSpriteId = 0;
static s16 sPlayerToMewDeltaX;
static s16 sPlayerToMewDeltaY;
static u8 sMewDirectionCandidates[4];
extern const struct SpritePalette gSpritePalette_GeneralFieldEffect1;
extern const struct SpriteTemplate *const gFieldEffectObjectTemplatePointers[];
static const s16 sFarawayIslandRockCoords[4][2] =
{
{14 + 7, 9 + 7},
{18 + 7, 9 + 7},
{ 9 + 7, 10 + 7},
{13 + 7, 13 + 7},
};
static u8 GetMewObjectEventId(void)
{
u8 objectEventId;
TryGetObjectEventIdByLocalIdAndMap(1, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &objectEventId);
return objectEventId;
}
// When the player enters Faraway Island interior it begins a "hide and seek" minigame where Mew disappears into the grass
// This function returns the direction Mew will take a step, and is run every time the player takes a step
u32 GetMewMoveDirection(void)
{
u8 i;
int mewSafeFromTrap;
struct ObjectEvent *mew = &gObjectEvents[GetMewObjectEventId()];
sPlayerToMewDeltaX = gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.x - mew->currentCoords.x;
sPlayerToMewDeltaY = gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.y - mew->currentCoords.y;
for (i = 0; i < ARRAY_COUNT(sMewDirectionCandidates); i++)
sMewDirectionCandidates[i] = DIR_NONE;
// Player hasn't moved (just facing new direction), don't move
if (gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.x == gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x
&& gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.y == gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y)
{
return DIR_NONE;
}
// Mew is invisible except for every 8th step
if (VarGet(VAR_FARAWAY_ISLAND_STEP_COUNTER) % 8 == 0)
mew->invisible = FALSE;
else
mew->invisible = TRUE;
// Mew will stay in place for 1 step after its visible
if (VarGet(VAR_FARAWAY_ISLAND_STEP_COUNTER) % 9 == 0)
return DIR_NONE;
// Below loop is for Mew to try to avoid getting trapped between the player and a rock
for (i = 0; i < ARRAY_COUNT(sFarawayIslandRockCoords); i++)
{
if (gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.x == sFarawayIslandRockCoords[i][0])
{
mewSafeFromTrap = FALSE;
if (gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.y < sFarawayIslandRockCoords[i][1])
{
if (mew->currentCoords.y <= sFarawayIslandRockCoords[i][1])
mewSafeFromTrap = TRUE;
}
else
{
if (mew->currentCoords.y >= sFarawayIslandRockCoords[i][1])
mewSafeFromTrap = TRUE;
}
if (!mewSafeFromTrap)
{
if (sPlayerToMewDeltaX > 0)
{
if (mew->currentCoords.x + 1 == gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.x)
{
if (CanMewMoveToCoords(mew->currentCoords.x + 1, mew->currentCoords.y))
return DIR_EAST;
}
}
else if (sPlayerToMewDeltaX < 0)
{
if (mew->currentCoords.x - 1 == gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.x)
{
if (CanMewMoveToCoords(mew->currentCoords.x - 1, mew->currentCoords.y))
return DIR_WEST;
}
}
if (mew->currentCoords.x == gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.x)
{
if (sPlayerToMewDeltaY > 0)
{
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y - 1))
return DIR_NORTH;
}
else
{
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y + 1))
return DIR_SOUTH;
}
}
}
}
if (gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.y == sFarawayIslandRockCoords[i][1])
{
mewSafeFromTrap = FALSE;
if (gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.x < sFarawayIslandRockCoords[i][0])
{
if (mew->currentCoords.x <= sFarawayIslandRockCoords[i][0])
mewSafeFromTrap = TRUE;
}
else
{
if (mew->currentCoords.x >= sFarawayIslandRockCoords[i][0])
mewSafeFromTrap = TRUE;
}
if (!mewSafeFromTrap)
{
if (sPlayerToMewDeltaY > 0)
{
if (mew->currentCoords.y + 1 == gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.y)
{
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y + 1))
return DIR_SOUTH;
}
}
else if (sPlayerToMewDeltaY < 0)
{
if (mew->currentCoords.y - 1 == gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.y)
{
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y - 1))
return DIR_NORTH;
}
}
if (mew->currentCoords.y == gObjectEvents[gPlayerAvatar.objectEventId].previousCoords.y)
{
if (sPlayerToMewDeltaX > 0)
{
if (CanMewMoveToCoords(mew->currentCoords.x - 1, mew->currentCoords.y))
return DIR_WEST;
}
else
{
if (CanMewMoveToCoords(mew->currentCoords.x + 1, mew->currentCoords.y))
return DIR_EAST;
}
}
}
}
}
// Check if Mew can move in any direction without getting closer to the player
// If so load into sMewDirectionCandidates
// If Mew can move in two of the checked directions, choose one randomly
if (ShouldMewMoveNorth(mew, 0))
{
if (ShouldMewMoveEast(mew, 1))
return GetRandomMewDirectionCandidate(2);
else if (ShouldMewMoveWest(mew, 1))
return GetRandomMewDirectionCandidate(2);
else
return DIR_NORTH;
}
if (ShouldMewMoveSouth(mew, 0))
{
if (ShouldMewMoveEast(mew, 1))
return GetRandomMewDirectionCandidate(2);
else if (ShouldMewMoveWest(mew, 1))
return GetRandomMewDirectionCandidate(2);
else
return DIR_SOUTH;
}
if (ShouldMewMoveEast(mew, 0))
{
if (ShouldMewMoveNorth(mew, 1))
return GetRandomMewDirectionCandidate(2);
else if (ShouldMewMoveSouth(mew, 1))
return GetRandomMewDirectionCandidate(2);
else
return DIR_EAST;
}
if (ShouldMewMoveWest(mew, 0))
{
if (ShouldMewMoveNorth(mew, 1))
return GetRandomMewDirectionCandidate(2);
else if (ShouldMewMoveSouth(mew, 1))
return GetRandomMewDirectionCandidate(2);
else
return DIR_WEST;
}
// If this point is reached, Mew cannot move without getting closer to the player
// Avoid player on same Y, try move North/South
if (sPlayerToMewDeltaY == 0)
{
if (gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y > mew->currentCoords.y)
{
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y - 1))
return DIR_NORTH;
}
if (gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y < mew->currentCoords.y)
{
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y + 1))
return DIR_SOUTH;
}
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y - 1))
return DIR_NORTH;
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y + 1))
return DIR_SOUTH;
}
// Avoid player on same X, try move West/East
if (sPlayerToMewDeltaX == 0)
{
if (gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x > mew->currentCoords.x)
{
if (CanMewMoveToCoords(mew->currentCoords.x - 1, mew->currentCoords.y))
return DIR_WEST;
}
if (gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x < mew->currentCoords.x)
{
if (CanMewMoveToCoords(mew->currentCoords.x + 1, mew->currentCoords.y))
return DIR_EAST;
}
if (CanMewMoveToCoords(mew->currentCoords.x + 1, mew->currentCoords.y))
return DIR_EAST;
if (CanMewMoveToCoords(mew->currentCoords.x - 1, mew->currentCoords.y))
return DIR_WEST;
}
// Can't avoid player on axis, move any valid direction
return GetValidMewMoveDirection(DIR_NONE);
}
// Mew can move to any Tall/Long Grass metatile the player isn't currently on
static bool8 CanMewMoveToCoords(s16 x, s16 y)
{
if (gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x == x
&& gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y == y)
{
return FALSE;
}
return MetatileBehavior_IsPokeGrass(MapGridGetMetatileBehaviorAt(x, y));
}
// Last ditch effort to move, clear move candidates and try all directions again
static u8 GetValidMewMoveDirection(u8 ignoredDir)
{
u8 i;
u8 count = 0;
struct ObjectEvent *mew = &gObjectEvents[GetMewObjectEventId()];
for (i = 0; i < ARRAY_COUNT(sMewDirectionCandidates); i++)
sMewDirectionCandidates[i] = DIR_NONE;
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y - 1) == TRUE && ignoredDir != DIR_NORTH)
{
sMewDirectionCandidates[count] = DIR_NORTH;
count++;
}
if (CanMewMoveToCoords(mew->currentCoords.x + 1, mew->currentCoords.y) == TRUE && ignoredDir != DIR_EAST)
{
sMewDirectionCandidates[count] = DIR_EAST;
count++;
}
if (CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y + 1) == TRUE && ignoredDir != DIR_SOUTH)
{
sMewDirectionCandidates[count] = DIR_SOUTH;
count++;
}
if (CanMewMoveToCoords(mew->currentCoords.x - 1, mew->currentCoords.y) == TRUE && ignoredDir != DIR_WEST)
{
sMewDirectionCandidates[count] = DIR_WEST;
count++;
}
if (count > 1)
return sMewDirectionCandidates[VarGet(VAR_FARAWAY_ISLAND_STEP_COUNTER) % count];
else
return sMewDirectionCandidates[0];
}
void UpdateFarawayIslandStepCounter(void)
{
u16 steps = VarGet(VAR_FARAWAY_ISLAND_STEP_COUNTER);
if (gSaveBlock1Ptr->location.mapNum == MAP_NUM(FARAWAY_ISLAND_INTERIOR)
&& gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(FARAWAY_ISLAND_INTERIOR))
{
steps++;
if (steps >= 9999)
VarSet(VAR_FARAWAY_ISLAND_STEP_COUNTER, 0);
else
VarSet(VAR_FARAWAY_ISLAND_STEP_COUNTER, steps);
}
}
bool8 ObjectEventIsFarawayIslandMew(struct ObjectEvent *objectEvent)
{
if (gSaveBlock1Ptr->location.mapNum == MAP_NUM(FARAWAY_ISLAND_INTERIOR)
&& gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(FARAWAY_ISLAND_INTERIOR))
{
if (objectEvent->graphicsId == OBJ_EVENT_GFX_MEW)
return TRUE;
}
return FALSE;
}
bool8 IsMewPlayingHideAndSeek(void)
{
if (gSaveBlock1Ptr->location.mapNum == MAP_NUM(FARAWAY_ISLAND_INTERIOR)
&& gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(FARAWAY_ISLAND_INTERIOR))
{
if (FlagGet(FLAG_CAUGHT_MEW) != TRUE && FlagGet(FLAG_HIDE_MEW) != TRUE)
return TRUE;
}
return FALSE;
}
// Every 4th step Mew will shake the grass it steps into
// Otherwise its movement leaves grass undisturbed
bool8 ShouldMewShakeGrass(struct ObjectEvent *objectEvent)
{
if (VarGet(VAR_FARAWAY_ISLAND_STEP_COUNTER) != 0xFFFF
&& VarGet(VAR_FARAWAY_ISLAND_STEP_COUNTER) % 4 == 0)
return TRUE;
return FALSE;
}
void SetMewAboveGrass(void)
{
s16 x;
s16 y;
u8 spriteId;
struct ObjectEvent *mew = &gObjectEvents[GetMewObjectEventId()];
mew->invisible = FALSE;
if (gSpecialVar_0x8004 == 1)
{
// For after battle where Mew should still be present (e.g. if ran from battle)
mew->fixedPriority = 1;
gSprites[mew->spriteId].subspriteMode = SUBSPRITES_IGNORE_PRIORITY;
gSprites[mew->spriteId].subpriority = 1;
}
else
{
// Mew emerging from grass when found
// Also do field effect for grass shaking as it emerges
VarSet(VAR_FARAWAY_ISLAND_STEP_COUNTER, 0xFFFF);
mew->fixedPriority = 1;
gSprites[mew->spriteId].subspriteMode = SUBSPRITES_IGNORE_PRIORITY;
if (gSpecialVar_Facing != DIR_NORTH)
gSprites[mew->spriteId].subpriority = 1;
LoadSpritePalette(&gSpritePalette_GeneralFieldEffect1);
UpdateSpritePaletteWithWeather(IndexOfSpritePaletteTag(gSpritePalette_GeneralFieldEffect1.tag));
x = mew->currentCoords.x;
y = mew->currentCoords.y;
SetSpritePosToOffsetMapCoords(&x, &y, 8, 8);
sGrassSpriteId = CreateSpriteAtEnd(gFieldEffectObjectTemplatePointers[FLDEFFOBJ_LONG_GRASS], x, y, gSprites[mew->spriteId].subpriority - 1);
if (sGrassSpriteId != MAX_SPRITES)
{
struct Sprite *sprite = &gSprites[sGrassSpriteId];
sprite->coordOffsetEnabled = 1;
sprite->oam.priority = 2;
sprite->callback = SpriteCallbackDummy;
}
}
}
void DestroyMewEmergingGrassSprite(void)
{
if (sGrassSpriteId != MAX_SPRITES)
DestroySprite(&gSprites[sGrassSpriteId]);
}
static bool8 ShouldMewMoveNorth(struct ObjectEvent *mew, u8 index)
{
if (sPlayerToMewDeltaY > 0 && CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y - 1))
{
sMewDirectionCandidates[index] = DIR_NORTH;
return TRUE;
}
return FALSE;
}
static bool8 ShouldMewMoveEast(struct ObjectEvent *mew, u8 index)
{
if (sPlayerToMewDeltaX < 0 && CanMewMoveToCoords(mew->currentCoords.x + 1, mew->currentCoords.y))
{
sMewDirectionCandidates[index] = DIR_EAST;
return TRUE;
}
return FALSE;
}
static bool8 ShouldMewMoveSouth(struct ObjectEvent *mew, u8 index)
{
if (sPlayerToMewDeltaY < 0 && CanMewMoveToCoords(mew->currentCoords.x, mew->currentCoords.y + 1))
{
sMewDirectionCandidates[index] = DIR_SOUTH;
return TRUE;
}
return FALSE;
}
static bool8 ShouldMewMoveWest(struct ObjectEvent *mew, u8 index)
{
if (sPlayerToMewDeltaX > 0 && CanMewMoveToCoords(mew->currentCoords.x - 1, mew->currentCoords.y))
{
sMewDirectionCandidates[index] = DIR_WEST;
return TRUE;
}
return FALSE;
}
static u8 GetRandomMewDirectionCandidate(u8 numDirections)
{
return sMewDirectionCandidates[VarGet(VAR_FARAWAY_ISLAND_STEP_COUNTER) % numDirections];
}